如何检查路径中是否存在程序

我正在用scala编写一个程序,调用:

Runtime.getRuntime().exec( "svn ..." ) 

我想检查命令行中是否有“svn”(即可以在PATH中访问)。 我怎样才能做到这一点 ?

PS:我的程序设计用于在Windows上运行

我不是scala程序员,但我会用任何语言做的,就是执行类似’ svn help ‘之类的东西来检查exec方法的返回码(0或1)…如果失败则svn不是在路径中:P

 Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("svn help"); int exitVal = proc.exitValue(); 

按照惯例,值0表示正常终止。

也许有人会对Java 8解决方案感兴趣:

 String exec = ; boolean existsInPath = Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator))) .map(Paths::get) .anyMatch(path -> Files.exists(path.resolve(exec))); 

顺便说一句,你可以用anyMatch(...)替换anyMatch(...) filter(...).findFirst() – 这样你就可以得到确切的可执行路径。

Selenium在类org.openqa.selenium.os.ExecutableFinder具有相当完整的Windows / Linux / Mac实现,自Selenium 3.1以来具有public访问权限(之前只能通过已弃用的方法org.openqa.selenium.os.CommandLine#find )。 虽然它是ASL 2.0。

请注意, ExecutableFinder不了解Windows上的PATHEXT – 它只有一组硬编码的可执行文件扩展名(.exe,.com,.bat)。

此代码在Windows上使用“where”命令,在其他系统上使用“which”命令,以检查系统是否知道PATH中所需的程序。 如果找到,则该函数将java.nio.file.Path返回给程序,否则返回null。

我在Windows 7和Linux Mint 17.3上使用Java 8进行了测试。

 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 / bin中/ PSQL

这种方法的优点是它应该可以在任何平台上运行,并且不需要解析PATH环境变量或查看注册表。 即使找到,也不会调用所需的程序。 最后,没有必要知道程序扩展。 Windows下的gnuplot.exe和Linux下的gnuplot都可以通过相同的代码找到:

  SimulationUtils.lookForProgramInPath("gnuplot") 

欢迎提出改进建议!

关于原始问题,我也会检查FMF建议的存在。

我还想指出,您必须至少处理该过程的输出,读取可用数据,以便不会将流填充到边缘。 否则,这将导致进程阻塞。

为此,使用proc.getInputStream()(对于System.out)和proc.getErrorStream()(对于System.err)检索进程的InputStream,并读取不同线程中的可用数据。

我只是告诉你,因为这是一个常见的陷阱,svn可能会产生相当多的输出,所以请不要为了offtopic而投票;)

如果你安装了cygwin,你可以先调用“which svn”,如果它在可执行路径中,它将返回svn的绝对路径,或者“which:no svn in(…)”。 如果找不到,“which”的调用将返回exitValue为1,如果找到则返回0。 您可以通过FMF详细信息的方式检查此错误代码。

根据我的经验,如果它退出与否,通过调用带有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; }