Как проверить наличие программы в пути - PullRequest
14 голосов
/ 01 июня 2009

Я пишу программу в Scala, которая вызывает:

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

Я хочу проверить, доступен ли svn из командной строки (т. Е. Он доступен в PATH). Как я могу это сделать?

PS: Моя программа предназначена для работы на Windows

Ответы [ 7 ]

18 голосов
/ 08 мая 2014

Может быть, кто-то заинтересуется решением 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() - чтобы получить точный путь к исполняемому файлу.

13 голосов
/ 01 июня 2009

Я не программист Scala, но то, что я хотел бы сделать на любом языке, - это выполнить что-то вроде 'svn help', просто чтобы проверить код возврата (0 или 1) метода exec ... в случае сбоя SVN не в пути: P

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

Условно, значение 0 указывает на нормальное завершение.

4 голосов
/ 14 января 2015

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

3 голосов
/ 28 июня 2016

этот код использует команду «где» в Windows и «какую» в других системах, чтобы проверить, знает ли система о нужной программе в PATH. Если найдено, функция возвращает java.nio.file.Path в программу, и в противном случае возвращает ноль.

Я тестировал его с 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")

Предложения по улучшению приветствуются!

2 голосов
/ 01 июня 2009

Что касается первоначального вопроса, я бы также проверил его существование, как предложил FMF.

Я также хотел бы отметить, что вам придется обрабатывать как минимум выходные данные процесса, считывая доступные данные, чтобы потоки не были заполнены до краев. Это может привести к блокировке процесса, в противном случае.

Для этого извлеките InputStreams процесса с помощью proc.getInputStream () (для System.out) и proc.getErrorStream () (для System.err) и прочитайте доступные данные в разных потоках.

Я просто говорю вам, потому что это распространенная ловушка, и svn потенциально может создать довольно много выходных данных, поэтому, пожалуйста, не понижайте голос за оффтоп;)

0 голосов
/ 02 ноября 2016

По моему опыту невозможно определить различные системы, просто вызвав команду с 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;
}
0 голосов
/ 01 июня 2009

Если у вас установлен cygwin, вы можете сначала вызвать «which svn», который вернет абсолютный путь к svn, если он находится в пути к исполняемому файлу, или же «which: no svn in (...)». Вызов «which» вернет значение exitValue, равное 1, если оно не найдено, или 0, если оно найдено. Вы можете проверить этот код ошибки в порядке FMF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...