2009-06-01 8 views
13

Sto scrivendo un programma in scala che chiamano:.Come verificare l'esistenza di un programma nel percorso

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

voglio verificare se "svn" è disponibile da linea di comando (cioè è raggiungibile nel PERCORSO). Come posso fare questo?

PS: Il mio programma è progettato per essere eseguito su Windows

risposta

13

Io non sono un programmatore di scala, ma quello che vorrei fare in qualsiasi lingua, è quello di eseguire qualcosa di simile a 'svn help' solo per controllare il codice di ritorno (0 o 1) del metodo exec ... se fallisce la svn non è nel percorso: P

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

per convenzione, il valore 0 indica normale terminazione.

+0

penso che sarebbe meglio fare "che svn" invece di "aiuto svn". Continuerà a fornire il codice di ritorno appropriato se svn esiste nel percorso, ma in caso di successo si otterrà anche il percorso completo all'eseguibile svn. – Apreche

+5

"which" non è un comando di Windows. – EMMERICH

+0

"where" è l'equivalente di Windows di "which" –

2

Per quanto riguarda la domanda iniziale, vorrei anche verificare l'esistenza come suggerito da FMF.

Vorrei anche precisare che dovrete gestire almeno l'output del processo, leggendo i dati disponibili in modo che i flussi non vengano riempiti fino all'orlo. Ciò farebbe sì che il processo blocchi, altrimenti.

Per eseguire questa operazione, recuperare gli stream di input del processo utilizzando proc.getInputStream() (per System.out) e proc.getErrorStream() (per System.err) e leggere i dati disponibili in thread diversi.

ho appena detto, perché questo è un errore comune e svn potenzialmente creare un po 'di uscita quindi per favore non downvote per offtopicness;)

0

Se è stato installato cygwin si potrebbe chiamare prima ", che svn ", che restituirà il percorso assoluto a svn se si trova nel percorso dell'eseguibile, oppure" which: no svn in (...) ". La chiamata a "which" restituirà un exitValue di 1 se non trovato, o 0 se viene trovato. È possibile controllare questo codice di errore nel modo con i dettagli FMF.

13

Forse qualcuno sarebbe interessato a Java 8 soluzione:

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

A proposito, si può sostituire con anyMatch(...)filter(...).findFirst() - così si otterrà il percorso dell'eseguibile esatto.

+0

Staresti meglio con 'Pattern.splitAsStream' ... –

+0

Quando provo questo ed eseguo il mio IDE (sto usando Eclipse), non riesce a trovare un file che ha avuto il suo percorso aggiunto al mio ambiente PATH variabile. Tuttavia, quando creo un JRE eseguibile da esso ed eseguo quello dal mio terminale, funziona. Quindi sospetto che il mio PERCORSO dall'interno del mio IDE non sia lo stesso del mio PERCORSO quando apro un terminale. Come posso aggirare questo? Preferirei non creare un Jar percorribile ogni volta che voglio testare il codice. Grazie! – skrilmps

+0

Anche io non riesco a farlo funzionare su Windows. Se imposto 'exec = java' ottengo un risultato falso. Ma se eseguo 'where java' da cmd ottengo un successo. – skrilmps

4

selenio ha quello che sembra essere un'implementazione ragionevolmente completo per Windows/Linux/Mac nella classe org.openqa.selenium.os.ExecutableFinder, con public accesso dal Selenio 3.1 (in precedenza accessibili solo tramite il metodo deprecato org.openqa.selenium.os.CommandLine#find). È ASL 2.0 però.

Nota che ExecutableFinder non capisce PATHEXT su Windows: ha solo un set codificato di estensioni di file eseguibili (.exe, .com, .bat).

+1

È pubblico ora: https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L48 – gouessej

+0

Grazie a @gouessej. Sembra che non faccia ancora parte di una versione: https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L35 – seanf

3

questo codice utilizza il comando "where" su Windows e il comando "which" su altri sistemi, per verificare se il sistema conosce il programma desiderato in PATH. Se trovato, la funzione restituisce un java.nio.file.Path al programma e null in caso contrario.

L'ho provato con Java 8 su Windows 7 e 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"); 
    } 
} 

Per utilizzarlo:

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

Sul mio sistema Windows 7, viene visualizzato:

C: \ Windows \ System32 \ notepad.exe

E su linux:

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

/usr/bin/psql

Il vantaggio di questo metodo è che dovrebbe funzionare su qualsiasi piattaforma e non c'è alcuna necessità di analizzare la variabile d'ambiente PATH o guardare il Registro di sistema. Il programma desiderato non viene mai chiamato, anche se trovato. Infine, non è necessario conoscere l'estensione del programma. gnuplot.exe sotto Windows e gnuplot sotto Linux verrebbero entrambi trovati con lo stesso codice:

SimulationUtils.lookForProgramInPath("gnuplot") 

Suggerimenti per il miglioramento sono i benvenuti!

+0

Questo in realtà ha prestazioni terribili. Chiamare i processi esterni dovrebbe essere evitato il più possibile. – BullyWiiPlaza

+1

@BullyWiiPlaza: Beh, non è stato neanche il mio obiettivo raggiungere buone prestazioni. Se hai idea di come potrebbe essere più veloce mentre lavori su Windows/Linux/MacOS, sentiti libero di suggerire qualsiasi cosa. A proposito, il risultato potrebbe essere memorizzato nella cache. Infine, l'obiettivo è chiamare un processo esterno. Qualsiasi chiamata 'svn' sarà probabilmente molto più lenta di' where' o 'which' call. –

+0

Sì, la risposta sopra di 'Dmitry Ginzburg' è veramente buona. 'where' ha un overhead relativamente grande (può essere superiore a 100 - 200ms) e se lo si chiama più volte non ha più le mani. Ho appena realizzato questo nel mio codice sul motivo per cui è stato notevolmente più lento. – BullyWiiPlaza

0

Nella mia esperienza, è impossibile dire nel corso dei vari sistemi attraverso solo chiamare un comando con il ProcessBuilder se esce o no (né Exceptions né restituire valori sembrano coerenti)

Così qui è una soluzione Java7 che attraversa la variabile di ambiente PATH e cerca uno strumento corrispondente. Controllerà tutti i file se la directory. Il matchesExecutable deve essere il nome dello strumento che ignora l'estensione e il caso.

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

Ecco l'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; 
}