How to check existence of a program in the path

0 votes
asked Jun 1, 2009 by steve-gury

I'm writing a program in scala which call:

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 ?

PS: My program is designed to be run on windows

7 Answers

0 votes
answered Jan 1, 2009 by jason-catena

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.

0 votes
answered Jun 1, 2009 by miguel-fonseca

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

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

By convention, the value 0 indicates normal termination.

0 votes
answered Jun 1, 2009 by huxi

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

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.

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

0 votes
answered Jun 8, 2014 by dmitry-ginzburg

Maybe someone would be interested in Java 8 solution:

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.

0 votes
answered Jun 14, 2015 by seanf

Selenium has what looks to be a reasonably complete implementation for Windows/Linux/Mac in the class org.openqa.selenium.os.ExecutableFinder, but unfortunately it doesn't have public access (except via the deprecated method org.openqa.selenium.os.CommandLine#find). It is ASL 2.0 though.

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

0 votes
answered Jan 1, 2016 by for3st

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)

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.

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;
}
0 votes
answered Jun 28, 2016 by eric-duminil

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.

I tested it with Java 8 on Windows 7 and 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");
    }
}

To use it :

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

On my Windows 7 system, it displays :

C:\Windows\System32\notepad.exe

And on 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 :

    SimulationUtils.lookForProgramInPath("gnuplot")

Suggestions for improvement are welcome!

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...