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

时间:2021-09-10 09:14:41

I'm writing a program in scala which call:

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

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

I want to check if "svn" is available from the commandline (ie. it is reachable in the PATH). How can I do this ?

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

PS: My program is designed to be run on windows

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

7 个解决方案

#1


I'm no scala programmer, but what I would do in any language, is to execute something like 'svn help' just to check the return code (0 or 1) of the exec method... if it fails the svn is not in the path :P

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

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

By convention, the value 0 indicates normal termination.

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

#2


Maybe someone would be interested in Java 8 solution:

也许有人会对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)));

By the way, you can replace anyMatch(...) with filter(...).findFirst() - so you'll get the exact executable path.

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

#3


Selenium has what looks to be a reasonably complete implementation for Windows/Linux/Mac in the class org.openqa.selenium.os.ExecutableFinder, with public access since Selenium 3.1 (previously only accessible via the deprecated method org.openqa.selenium.os.CommandLine#find). It is ASL 2.0 though.

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

Note that ExecutableFinder doesn't understand PATHEXT on Windows - it just has a hard-coded set of executable file extensions (.exe, .com, .bat).

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

#4


this code uses "where" command on Windows, and "which" command on other systems, to check if the system knows about the desired program in PATH. If found, the function returns a java.nio.file.Path to the program, and null otherwise.

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

I tested it with Java 8 on Windows 7 and Linux Mint 17.3.

我在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");
    }
}

To use it :

要使用它:

    System.out.println(SimulationUtils.lookForProgramInPath("notepad"));

On my Windows 7 system, it displays :

在我的Windows 7系统上,它显示:

C:\Windows\System32\notepad.exe

And on linux :

在linux上:

    System.out.println(SimulationUtils.lookForProgramInPath("psql"));

/usr/bin/psql

The advantage of this method is that it should work on any platform and there's no need to parse the PATH environment variable or look at the registry. The desired program is never called, even if found. Finally, there's no need to know the program extension. gnuplot.exe under Windows and gnuplot under Linux would both be found by the same code :

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

    SimulationUtils.lookForProgramInPath("gnuplot")

Suggestions for improvement are welcome!

欢迎提出改进建议!

#5


Concerning the original question I'd also check for existence as FMF suggested.

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

I'd also like to point out that you'll have to handle at least the output of the process, reading available data so the streams won't be filled to the brim. This would cause the process to block, otherwise.

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

To do this, retrieve the InputStreams of the process using proc.getInputStream() (for System.out) and proc.getErrorStream() (for System.err) and read available data in different threads.

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

I just tell you because this is a common pitfall and svn will potentially create quite a bit of output so please don't downvote for offtopicness ;)

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

#6


If you have cygwin installed you could first call "which svn", which will return the absolute path to svn if it's in the executable path, or else "which: no svn in (...)". The call to "which" will return an exitValue of 1 if not found, or 0 if it is found. You can check this error code in the manner FMF details.

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

#7


In my experience it is impossible to tell over the various systems through just calling a the command with the ProcessBuilder if it exits or not (neither Exceptions nor return values seem consistent)

根据我的经验,如果它退出与否,通过调用带有ProcessBuilder的命令就不可能告诉各种系统(异常和返回值似乎都不一致)

So here is a Java7 solution that traverses the PATH environment variable and looks for a matching tool. Will check all files if directory. The matchesExecutable must be the name of the tool ignoring extension and case.

所以这是一个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;
}

Here are the helper:

这是帮手:

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;
}

#1


I'm no scala programmer, but what I would do in any language, is to execute something like 'svn help' just to check the return code (0 or 1) of the exec method... if it fails the svn is not in the path :P

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

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

By convention, the value 0 indicates normal termination.

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

#2


Maybe someone would be interested in Java 8 solution:

也许有人会对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)));

By the way, you can replace anyMatch(...) with filter(...).findFirst() - so you'll get the exact executable path.

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

#3


Selenium has what looks to be a reasonably complete implementation for Windows/Linux/Mac in the class org.openqa.selenium.os.ExecutableFinder, with public access since Selenium 3.1 (previously only accessible via the deprecated method org.openqa.selenium.os.CommandLine#find). It is ASL 2.0 though.

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

Note that ExecutableFinder doesn't understand PATHEXT on Windows - it just has a hard-coded set of executable file extensions (.exe, .com, .bat).

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

#4


this code uses "where" command on Windows, and "which" command on other systems, to check if the system knows about the desired program in PATH. If found, the function returns a java.nio.file.Path to the program, and null otherwise.

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

I tested it with Java 8 on Windows 7 and Linux Mint 17.3.

我在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");
    }
}

To use it :

要使用它:

    System.out.println(SimulationUtils.lookForProgramInPath("notepad"));

On my Windows 7 system, it displays :

在我的Windows 7系统上,它显示:

C:\Windows\System32\notepad.exe

And on linux :

在linux上:

    System.out.println(SimulationUtils.lookForProgramInPath("psql"));

/usr/bin/psql

The advantage of this method is that it should work on any platform and there's no need to parse the PATH environment variable or look at the registry. The desired program is never called, even if found. Finally, there's no need to know the program extension. gnuplot.exe under Windows and gnuplot under Linux would both be found by the same code :

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

    SimulationUtils.lookForProgramInPath("gnuplot")

Suggestions for improvement are welcome!

欢迎提出改进建议!

#5


Concerning the original question I'd also check for existence as FMF suggested.

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

I'd also like to point out that you'll have to handle at least the output of the process, reading available data so the streams won't be filled to the brim. This would cause the process to block, otherwise.

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

To do this, retrieve the InputStreams of the process using proc.getInputStream() (for System.out) and proc.getErrorStream() (for System.err) and read available data in different threads.

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

I just tell you because this is a common pitfall and svn will potentially create quite a bit of output so please don't downvote for offtopicness ;)

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

#6


If you have cygwin installed you could first call "which svn", which will return the absolute path to svn if it's in the executable path, or else "which: no svn in (...)". The call to "which" will return an exitValue of 1 if not found, or 0 if it is found. You can check this error code in the manner FMF details.

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

#7


In my experience it is impossible to tell over the various systems through just calling a the command with the ProcessBuilder if it exits or not (neither Exceptions nor return values seem consistent)

根据我的经验,如果它退出与否,通过调用带有ProcessBuilder的命令就不可能告诉各种系统(异常和返回值似乎都不一致)

So here is a Java7 solution that traverses the PATH environment variable and looks for a matching tool. Will check all files if directory. The matchesExecutable must be the name of the tool ignoring extension and case.

所以这是一个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;
}

Here are the helper:

这是帮手:

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;
}