2009-06-01 15 views
13

Piszę program w Scala, które nazywamy.Jak sprawdzić istnienie programu w ścieżce

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

Chcę sprawdzić, czy „svn” jest dostępne z linii poleceń (czyli jest osiągalny na ścieżce). Jak mogę to zrobić?

PS: Mój program jest przeznaczony do pracy w systemie Windows

Odpowiedz

13

jestem programista nie scala, ale to, co chciałbym zrobić w dowolnym języku, to aby wykonać coś jak „svn help” tylko, aby sprawdzić kod zwrotny (0 lub 1) metody exec ..., jeśli nie svn nie znajduje się w ścieżce: P

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

Umownie, wartość 0 oznacza normalne zakończenie.

+0

myślę, że byłoby lepiej, aby zrobić "który svn" zamiast "svn help". Nadal będzie podawał prawidłowy kod powrotu, czy svn istnieje w ścieżce, czy też nie, ale po sukcesie otrzymasz pełną ścieżkę do pliku wykonywalnego svn. – Apreche

+5

"który" nie jest poleceniem Windows. – EMMERICH

+0

"gdzie" jest odpowiednikiem Windowsa "który" –

2

Odnośnie pierwotnego pytania, sprawdziłbym również istnienie, jak zasugerował FMF.

Chciałbym również zaznaczyć, że będziesz musiał obsłużyć co najmniej dane wyjściowe procesu, odczytując dostępne dane, aby strumienie nie zostały wypełnione po brzegi. To spowodowałoby zablokowanie procesu, w przeciwnym razie.

Aby to zrobić, pobierz InputStreams procesu za pomocą proc.getInputStream() (dla System.out) i proc.getErrorStream() (dla System.err) i odczytaj dostępne dane w różnych wątkach.

po prostu powiedzieć, ponieważ jest to wspólny pułapka i svn potencjalnie stworzyć sporo wyjściu więc proszę nie downvote dla offtopicness;)

0

Jeśli Cygwin zainstalowany można najpierw wywołać „, które svn ", która zwróci absolutną ścieżkę do svn, jeśli znajduje się w ścieżce wykonywalnej, lub" która: no svn in (...) ". Wywołanie "which" zwróci wartość exitValue 1, jeśli nie zostanie znaleziona, lub 0, jeśli zostanie znaleziona. Możesz sprawdzić ten kod błędu w taki sposób, jak szczegóły FMF.

13

Może ktoś byłby zainteresowany Java 8 rozwiązanie:

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

Nawiasem mówiąc, można zastąpić anyMatch(...) z filter(...).findFirst() - tak dostaniesz dokładną ścieżkę pliku wykonywalnego.

+0

Lepiej poradzisz sobie z 'Pattern.splitAsStream' ... –

+0

Kiedy próbuję tego i uruchomię to w moim IDE (używam Eclipse), nie mogę znaleźć pliku, który ma swoją ścieżkę dodaną do mojego środowiska PATH zmienna. Jednak po utworzeniu działającego JRE i uruchomieniu go z mojego terminala działa. Podejrzewam, że moja ścieżka z wewnątrz IDE nie jest taka sama jak moja ścieżka, gdy otwieram terminal. Jak mogę to obejść? Wolałbym nie wykonywać sagów, które można uruchomić, za każdym razem, gdy chcę przetestować kod. Dzięki! – skrilmps

+0

Nie dostaję tego również do pracy w systemie Windows. Jeśli ustawię 'exec = java', otrzymam fałszywy wynik. Ale jeśli uruchomię 'where java' z cmd, otrzymam trafienie. – skrilmps

4

Selen ma co wydaje się być rozsądnie pełna realizacja dla Windows/Linux/Mac w klasie org.openqa.selenium.os.ExecutableFinder z public dostępem od Selen 3.1 (wcześniej dostępne tylko za pośrednictwem METODA org.openqa.selenium.os.CommandLine#find). Jest to jednak ASL 2.0.

Należy pamiętać, że ExecutableFinder nie rozumie PATHEXT w systemie Windows - ma po prostu zakodowany zestaw wykonywalnego rozszerzenia plików (.exe, .com, .bat).

+1

To jest teraz publiczne: https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L48 – gouessej

+0

Dzięki @gouessej. Wygląda na to, że nie jest jeszcze częścią wydania: https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/java/client/src/org/openqa/selenium/os/ExecutableFinder.JAVA#L35 – seanf

3

ten kod wykorzystuje polecenie "where" w systemie Windows i polecenie "which" w innych systemach, aby sprawdzić, czy system wie o pożądanym programie w PATH. Jeśli zostanie znaleziona, funkcja zwróci plik java.nio.file.Path do programu i null w przeciwnym razie.

Przetestowałem to z Java 8 na Windows 7 i 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"); 
    } 
} 

Aby go użyć:

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

W moim systemie Windows 7 wyświetla:

C: \ Windows \ System32 \ notepad.exe

I na Linux:

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

/usr/bin/psql

Zaletą tej metody jest to, że powinien działać na każdej platformie i nie ma potrzeby analizowania zmiennej środowiskowej PATH lub szukać w rejestrze. Żądany program nigdy nie jest wywoływany, nawet jeśli został znaleziony. Wreszcie, nie trzeba znać rozszerzenia programu. gnuplot.exe w systemie Windows i gnuplot pod Linuksem można znaleźć pod tym samym kodem:

SimulationUtils.lookForProgramInPath("gnuplot") 

Sugestie do poprawy są mile widziane!

+0

To naprawdę ma straszliwą wydajność. W miarę możliwości należy unikać wywoływania procesów zewnętrznych. – BullyWiiPlaza

+1

@BullyWiiPlaza: Osiągnięcie dobrej wydajności nie było moim celem. Jeśli masz pojęcie, w jaki sposób może być szybszy, a jednocześnie działa w systemie Windows/Linux/MacOS, możesz zasugerować cokolwiek. BTW, wynik może być buforowany. Wreszcie, celem jest wywołanie zewnętrznego procesu. Każde wywołanie 'svn' będzie prawdopodobnie znacznie wolniejsze niż' where' lub 'which' call. –

+0

Tak, powyższa odpowiedź 'Dmitry Ginzburg' jest naprawdę dobra. 'where' ma stosunkowo duży narzut (może być większy niż 100 - 200ms) i jeśli wywołasz go wiele razy, to wymyka się z rąk. Właśnie zdałem sobie sprawę z tego w moim kodzie, dlaczego było zauważalnie wolniej. – BullyWiiPlaza

0

Z mojego doświadczenia wynika, że ​​jest niemożliwe, aby powiedzieć nad różnymi systemami poprzez właśnie wywołanie polecenia z ProcessBuilder jeśli to wychodzi, czy nie (ani Exceptions ani powrócić wartości wydają się spójne)

Więc tutaj jest rozwiązanie Java7 że przechodzi przez zmienną środowiskową PATH i szuka odpowiedniego narzędzia. Sprawdzi wszystkie pliki, jeśli katalog. matchesExecutable musi być nazwą narzędzia ignorującego rozszerzenie i wielkość liter.

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

Oto pomocnik:

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; 
} 
Powiązane problemy