J'ai l'exemple de code suivant ci-dessous. echo test
Grâce à quoi vous pouvez entrer une commande dans le shell bash ie et avoir le résultat en écho. Cependant, après la première lecture. Les autres flux de sortie ne fonctionnent pas?
Pourquoi est-ce ou est-ce que je fais quelque chose de mal? Mon objectif final est de créer une tâche programmée Threaded qui exécute une commande périodiquement vers / bash afin que OutputStream
et InputStream
doive travailler en tandem et ne pas cesser de fonctionner. J'ai également rencontré l'erreur java.io.IOException: Broken pipe
des idées?
Merci.
String line;
Scanner scan = new Scanner(System.in);
Process process = Runtime.getRuntime ().exec ("/bin/bash");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Réponses:
Tout d'abord, je recommanderais de remplacer la ligne
avec les lignes
ProcessBuilder est nouveau dans Java 5 et facilite l'exécution des processus externes. À mon avis, son amélioration la plus significative
Runtime.getRuntime().exec()
est qu'il vous permet de rediriger l'erreur standard du processus enfant dans sa sortie standard. Cela signifie que vous n'en avez qu'un seulInputStream
à lire. Avant cela, vous deviez avoir deux threads séparés, une lecture à partir destdout
et une lecture à partir destderr
, pour éviter que le tampon d'erreur standard ne se remplisse alors que le tampon de sortie standard était vide (provoquant le blocage du processus enfant), ou vice versa.Ensuite, les boucles (dont vous avez deux)
quitte uniquement lorsque le
reader
, qui lit la sortie standard du processus, retourne la fin du fichier. Cela se produit uniquement lorsque lebash
processus se termine. Il ne retournera pas de fin de fichier s'il se trouve actuellement qu'il n'y a plus de sortie du processus. Au lieu de cela, il attendra la prochaine ligne de sortie du processus et ne retournera pas avant d'avoir cette ligne suivante.Puisque vous envoyez deux lignes d'entrée au processus avant d'atteindre cette boucle, la première de ces deux boucles se bloquera si le processus n'est pas sorti après ces deux lignes d'entrée. Il restera là en attendant qu'une autre ligne soit lue, mais il n'y aura jamais d'autre ligne à lire.
J'ai compilé votre code source (je suis sous Windows pour le moment, donc j'ai remplacé
/bin/bash
parcmd.exe
, mais les principes devraient être les mêmes), et j'ai trouvé que:echo test
et ensuiteexit
, le programme sort de la première boucle depuis la fin ducmd.exe
processus. Le programme demande alors une autre ligne d'entrée (qui est ignorée), saute directement sur la deuxième boucle puisque le processus fils est déjà sorti, puis se ferme.exit
et puisecho test
, j'obtiens une IOException se plaignant de la fermeture d'un tuyau. Il faut s'y attendre - la première ligne d'entrée a entraîné la fermeture du processus et il n'y a nulle part où envoyer la deuxième ligne.J'ai vu une astuce qui fait quelque chose de similaire à ce que vous semblez vouloir, dans un programme sur lequel je travaillais auparavant. Ce programme conservait un certain nombre de shells, y exécutait des commandes et lisait la sortie de ces commandes. L'astuce utilisée était de toujours écrire une ligne «magique» qui marque la fin de la sortie de la commande shell, et de l'utiliser pour déterminer quand la sortie de la commande envoyée au shell était terminée.
J'ai pris votre code et j'ai tout remplacé après la ligne affectée
writer
par la boucle suivante:Après avoir fait cela, je pourrais exécuter de manière fiable quelques commandes et que la sortie de chacune me revienne individuellement.
Les deux
echo --EOF--
commandes dans la ligne envoyée au shell sont là pour garantir que la sortie de la commande se termine avec--EOF--
même le résultat d'une erreur de la commande.Bien entendu, cette approche a ses limites. Ces limitations incluent:
--EOF--
.bash
signale une erreur de syntaxe et quitte si vous entrez du texte avec un)
.Ces points peuvent ne pas vous intéresser si tout ce que vous envisagez d'exécuter en tant que tâche planifiée va être limité à une commande ou à un petit ensemble de commandes qui ne se comporteront jamais de manière aussi pathologique.
EDIT : améliorez la gestion des sorties et d'autres modifications mineures suite à son exécution sous Linux.
la source
Je pense que vous pouvez utiliser un thread comme demon-thread pour lire votre entrée et votre lecteur de sortie sera déjà en boucle while dans le thread principal afin que vous puissiez lire et écrire en même temps.Vous pouvez modifier votre programme comme ceci:
et vous pouvez lire sera le même que ci-dessus ie
rendre votre rédacteur comme final sinon il ne pourra pas être accessible par classe interne.
la source
Vous avez
writer.close();
dans votre code. Alors bash reçoit EOF sur sonstdin
et sort. Ensuite, vous obtenezBroken pipe
en essayant de lire à partir dustdout
bash défunt.la source