2009-12-30 5 views
1

Actuellement, j'utilise ProcessBuilder pour exécuter des commandes à partir d'un serveur Java. Ce serveur remplace un ancien serveur Perl et une grande partie de notre code hérité spécifie des lignes de commande spécifiques à la plate-forme.Exécution d'une ligne de commande non codifiée à partir de Java

Par exemple, sur Windows, il peut faire:

command -option "hello world" 

et sur unix il pourrait faire:

command -option 'hello world' 

Le problème est que ProcessBuilder et Runtime.exec prennent tous les deux en lignes de commande lexicalisés (par exemple, {"command", "-option", "hello world"} pour unix et windows).

Alors que je préfère la plate-forme indépendante, nous avons quelque part dans la gamme de 30 millions de lignes de code perl dans notre code. Sans moi écrire un tokenizer pour les différentes plates-formes (pas vraiment un gros problème, je ne veux pas faire de WTF), est-il possible de laisser le shell sur le système d'exploitation tokenize la ligne de commande?

+0

'commande -option "Bonjour tout le monde"' œuvres sur unix et , citations sont des citations ... – akuhn

+0

Quoi qu'il en soit, notre code conditionne sur Windows vs Unix, généralement parce que les commandes sont plus complexes que cela et ont des citations imbriquées et des variables de ligne de commande et d'autres non-sens. – tster

+0

30 millions de lignes de perl?!? Je suis tellement content que je ne suis pas vous;) – Fantius

Répondre

7

Etes-vous capable d'utiliser le Runtime.exec(String) surchargé qui prend une seule chaîne et l'exécute en tant que commande entière?


Les travaux suivants pour moi sur Windows:

Process p = Runtime.getRuntime().exec("perl -e \"print 5\""); 
System.out.println(IOUtils.toString(p.getInputStream())); 
p.destroy(); 

Ceci est plus ou moins ce que Runtime.exec (String) fait:

public static void main(String [] args) throws Exception { 
    Process p = new ProcessBuilder(getCommand("perl -e \"print 5\"")).start(); 
    System.out.println(IOUtils.toString(p.getInputStream())); 
    p.destroy(); 

} 

private static String[] getCommand(String input) { 
    StringTokenizer tokenizer = new StringTokenizer(input); 
    String[] result = new String[tokenizer.countTokens()]; 
    for (int i = 0; tokenizer.hasMoreTokens(); i++) { 
     result[i] = tokenizer.nextToken(); 
    } 
    return result; 
} 
+0

Perl est sur le chemin de l'environnement dans lequel le processus s'exécute? – Kevin

+0

Oups, je viens de réaliser que j'utilisais ProcessBuilder, pas Runtime.exec(). – tster

+0

Est-il possible d'utiliser Runtime.exec() sans perdre la possibilité de rediriger stderr vers stdout? – tster

5

Je pense que la les citations sont interprétées par le shell. Au lieu de cela, mettre la commande dans un script shell:

$ cat temp.sh 
#!/bin/sh 
perl -e "print 5" 

et l'exécuter:

import java.io.BufferedReader; 
import java.io.InputStreamReader; 

public class PBTest { 

    public static void main(String[] args) { 
     ProcessBuilder pb = new ProcessBuilder("./temp.sh"); 
     pb.redirectErrorStream(true); 
     try { 
      Process p = pb.start(); 
      String s; 
      BufferedReader stdout = new BufferedReader (
       new InputStreamReader(p.getInputStream())); 
      while ((s = stdout.readLine()) != null) { 
       System.out.println(s); 
      } 
      System.out.println("Exit value: " + p.waitFor()); 
      p.getInputStream().close(); 
      p.getOutputStream().close(); 
      p.getErrorStream().close(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

Console:

5 
Exit value: 0 
Questions connexes