Как проверить наличие программы на пути
Я пишу программу в scala, которая вызывает:
Runtime.getRuntime().exec( "svn ..." )
Я хочу проверить, доступно ли "svn" из командной строки (т.е. доступно в PATH).
Как я могу это сделать?
PS: Моя программа предназначена для работы в Windows
Ответы
Ответ 1
Я не программист scala, но то, что я хотел бы сделать на любом языке, - это выполнить что-то вроде "svn help
", чтобы проверить код возврата (0 или 1) метода exec... if он не работает, svn не находится в пути: P
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("svn help");
int exitVal = proc.exitValue();
По соглашению, значение 0 указывает на нормальное завершение.
Ответ 2
Возможно, кому-то будет интересно решение Java 8:
String exec = <executable name>;
boolean existsInPath = Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator)))
.map(Paths::get)
.anyMatch(path -> Files.exists(path.resolve(exec)));
Кстати, вы можете заменить anyMatch(...)
на filter(...).findFirst()
- так что вы получите точный исполняемый путь.
Ответ 3
Selenium имеет достаточно реалистичную реализацию для Windows/Linux/Mac в классе org.openqa.selenium.os.ExecutableFinder
, с public
доступ с Selenium 3.1 (ранее доступный только через устаревший метод org.openqa.selenium.os.CommandLine#find
). Это ASL 2.0, хотя.
Обратите внимание, что ExecutableFinder
не понимает PATHEXT
в Windows - он просто имеет жестко запрограммированный набор исполняемых расширений файлов (.exe,.com,.bat).
Ответ 4
этот код использует команду "where" в Windows и "какая" команда в других системах, чтобы проверить, знает ли система о желаемой программе в PATH. Если найдено, функция возвращает java.nio.file.Path в программу, а null - в противном случае.
Я тестировал его с помощью Java 8 на Windows 7 и Linux Mint 17.3.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;
public class SimulationUtils
{
private final static Logger LOGGER = Logger.getLogger(SimulationUtils.class.getName());
public static Path lookForProgramInPath(String desiredProgram) {
ProcessBuilder pb = new ProcessBuilder(isWindows() ? "where" : "which", desiredProgram);
Path foundProgram = null;
try {
Process proc = pb.start();
int errCode = proc.waitFor();
if (errCode == 0) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
foundProgram = Paths.get(reader.readLine());
}
LOGGER.info(desiredProgram + " has been found at : " + foundProgram);
} else {
LOGGER.warning(desiredProgram + " not in PATH");
}
} catch (IOException | InterruptedException ex) {
LOGGER.warning("Something went wrong while searching for " + desiredProgram);
}
return foundProgram;
}
private static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
}
Чтобы использовать его:
System.out.println(SimulationUtils.lookForProgramInPath("notepad"));
В моей системе Windows 7 отображается:
C:\Windows\System32\notepad.exe
И на linux:
System.out.println(SimulationUtils.lookForProgramInPath("psql"));
/USR/бен/PSQL
Преимущество этого метода заключается в том, что он должен работать на любой платформе, и нет необходимости анализировать переменную среды PATH или просматривать реестр. Желаемая программа никогда не вызывается, даже если она найдена. Наконец, нет необходимости знать расширение программы. gnuplot.exe под Windows и gnuplot под Linux будут найдены одним и тем же кодом:
SimulationUtils.lookForProgramInPath("gnuplot")
Предложения по улучшению приветствуются!
Ответ 5
Что касается исходного вопроса, я бы также проверял существование, как предположил FMF.
Я также хотел бы указать, что вам придется обрабатывать хотя бы выходные данные процесса, читая доступные данные, чтобы потоки не были заполнены до краев. Это приведет к блокировке процесса.
Чтобы сделать это, извлеките InputStreams процесса, используя proc.getInputStream() (для System.out) и proc.getErrorStream() (для System.err) и прочитайте доступные данные в разных потоках.
Я просто скажу вам, потому что это обычная ошибка, и svn потенциально может создать довольно много выходных данных, поэтому, пожалуйста, не используйте downtote для offtopicness;)
Ответ 6
Если у вас установлен cygwin, вы можете сначала вызвать "which svn", который вернет абсолютный путь к svn, если он находится в исполняемом пути, или "который: no svn in (...)". Вызов "which" вернет exitValue из 1, если не найден, или 0, если он найден. Вы можете проверить этот код ошибки в виде данных FMF.
Ответ 7
По моему опыту невозможно рассказать по различным системам, просто вызывая команду с ProcessBuilder
, если она выходит или нет (ни Exceptions
, ни возвращаемые значения не кажутся непротиворечивыми)
Итак, вот решение Java7, которое пересекает переменную среды PATH
и ищет соответствующий инструмент. Будет проверять все файлы, если каталог. matchesExecutable
должно быть именем инструмента, игнорирующего расширение и регистр.
public static File checkAndGetFromPATHEnvVar(final String matchesExecutable) {
String[] pathParts = System.getenv("PATH").split(File.pathSeparator);
for (String pathPart : pathParts) {
File pathFile = new File(pathPart);
if (pathFile.isFile() && pathFile.getName().toLowerCase().contains(matchesExecutable)) {
return pathFile;
} else if (pathFile.isDirectory()) {
File[] matchedFiles = pathFile.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return FileUtil.getFileNameWithoutExtension(pathname).toLowerCase().equals(matchesExecutable);
}
});
if (matchedFiles != null) {
for (File matchedFile : matchedFiles) {
if (FileUtil.canRunCmd(new String[]{matchedFile.getAbsolutePath()})) {
return matchedFile;
}
}
}
}
}
return null;
}
Вот помощник:
public static String getFileNameWithoutExtension(File file) {
String fileName = file.getName();
int pos = fileName.lastIndexOf(".");
if (pos > 0) {
fileName = fileName.substring(0, pos);
}
return fileName;
}
public static boolean canRunCmd(String[] cmd) {
try {
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
try (BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
while ((inStreamReader.readLine()) != null) {
}
}
process.waitFor();
} catch (Exception e) {
return false;
}
return true;
}
Ответ 8
Это похоже на ответ Dmitry Ginzburg
, но также учитывает редкий случай, когда кто-то имеет неверный путь в переменной среды PATH
. Это может привести к InvalidPathException
.
private static final String ENVIRONMENT_VARIABLES_TEXT = System.getenv("PATH");
private static boolean isCommandAvailable(String executableFileName)
{
String[] environmentVariables = ENVIRONMENT_VARIABLES_TEXT.split(File.pathSeparator);
for (String environmentVariable : environmentVariables)
{
try
{
Path environmentVariablePath = Paths.get(environmentVariable);
if (Files.exists(environmentVariablePath))
{
Path resolvedEnvironmentVariableFilePath = environmentVariablePath.resolve(executableFileName);
if (Files.isExecutable(resolvedEnvironmentVariableFilePath))
{
return true;
}
}
} catch (InvalidPathException exception)
{
exception.printStackTrace();
}
}
return false;
}
В целом это может быть наиболее эффективным и надежным решением.