Considérez le code suivant:
String commandf = "ls /etc | grep release";
try {
// Execute the command and wait for it to complete
Process child = Runtime.getRuntime().exec(commandf);
child.waitFor();
// Print the first 16 bytes of its output
InputStream i = child.getInputStream();
byte[] b = new byte[16];
i.read(b, 0, b.length);
System.out.println(new String(b));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
La sortie du programme est:
/etc:
adduser.co
Lorsque je cours depuis le shell, bien sûr, cela fonctionne comme prévu:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
Les internets me disent que, étant donné que le comportement des tuyaux n'est pas multiplateforme, les esprits brillants qui travaillent dans l'usine Java produisant Java ne peuvent pas garantir que les tuyaux fonctionnent.
Comment puis-je faire ceci?
Je ne vais pas faire tout mon analyse en utilisant des constructions Java plutôt que grep
et sed
, parce que si je veux changer de langage, je serai obligé de réécrire mon code d'analyse dans ce langage, ce qui est totalement interdit.
Comment puis-je faire en sorte que Java effectue le piping et la redirection lors de l'appel de commandes shell?
java
exec
runtime.exec
poundifdef
la source
la source
command | grep foo
vous êtes beaucoup mieux avec juste d'exécutercommand
et de filtrer nativement en Java. Cela rend votre code un peu plus complexe, mais vous réduisez également considérablement la consommation globale de ressources et la surface d'attaque.Réponses:
Écrivez un script et exécutez le script au lieu de commandes séparées.
Le tuyau fait partie de la coque, vous pouvez donc également faire quelque chose comme ceci:
la source
ls
iels -lrt
?android
version ici, utilisez-la à la/system/bin/sh
placeJ'ai rencontré un problème similaire sous Linux, sauf que c'était "ps -ef | grep someprocess".
Au moins avec "ls", vous avez un remplacement Java indépendant du langage (bien que plus lent). Par exemple.:
Avec "ps", c'est un peu plus difficile, car Java ne semble pas avoir d'API pour cela.
J'ai entendu dire que Sigar pourrait peut-être nous aider: https://support.hyperic.com/display/SIGAR/Home
La solution la plus simple, cependant, (comme l'a souligné Kaj) est d'exécuter la commande piped sous la forme d'un tableau de chaînes. Voici le code complet:
Quant à savoir pourquoi le tableau String fonctionne avec pipe, alors qu'une seule chaîne ne le fait pas ... c'est l'un des mystères de l'univers (surtout si vous n'avez pas lu le code source). Je soupçonne que c'est parce que lorsque exec reçoit une seule chaîne, il l'analyse en premier (d'une manière que nous n'aimons pas). En revanche, lorsque exec reçoit un tableau de chaînes, il le transmet simplement au système d'exploitation sans l'analyser.
En fait, si nous prenons le temps d'une journée bien remplie et regardons le code source (à http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/ Runtime.java # Runtime.exec% 28java.lang.String% 2Cjava.lang.String []% 2Cjava.io.File% 29 ), nous trouvons que c'est exactement ce qui se passe:
la source
Créez un Runtime pour exécuter chacun des processus. Récupérez le OutputStream du premier Runtime et copiez-le dans le InputStream du second.
la source
La réponse acceptée par @Kaj est pour Linux. C'est l'équivalent pour Windows:
la source