2010-11-18 20 views
0

J'ai un programme Java qui exécute sh en mode interactif en tant que sous-processus. L'entrée est copiée à partir de System.in et la sortie est copiée à System.out. Tout fonctionne très bien, sauf que lorsque l'exécution de commandes telles que pwd dans ce shell interactif la sortie apparaît dans un mauvais ordre, par exemple:Pourquoi la sortie du sous-processus est-elle dans le mauvais ordre?

$ pwd 
$ /home/viz/workspace 

au lieu de

$ pwd 
/home/viz/workspace 
$ 

La différence est que dans le premier cas l'invite $ est imprimée avant la sortie de pwd.

Des idées pourquoi cela arrive-t-il et comment y remédier?

Voici le code:

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 

class StreamCopier implements Runnable { 
    private InputStream in; 
    private OutputStream out; 

    public StreamCopier(InputStream in, OutputStream out) { 
     this.in = in; 
     this.out = out; 
    } 

    public void run() { 
     try { 
      int n; 
      byte[] buffer = new byte[4096]; 
      while ((n = in.read(buffer)) != -1) { 
       out.write(buffer, 0, n); 
       out.flush(); 
      } 
      out.close(); 
     } 
     catch (IOException e) { 
      System.out.println(e); 
     } 
    } 
} 

public class Test { 
    public static void main(String[] args) 
      throws IOException, InterruptedException { 
     Process process = Runtime.getRuntime().exec("sh -i +m"); 
     Thread outThread = new Thread(new StreamCopier(
       process.getInputStream(), System.out)); 
     outThread.start(); 
     Thread errThread = new Thread(new StreamCopier(
       process.getErrorStream(), System.err)); 
     errThread.start(); 
     Thread inThread = new Thread(new StreamCopier(
       System.in, process.getOutputStream())); 
     inThread.start(); 
     process.waitFor(); 
     outThread.join(); 
     errThread.join(); 
     inThread.join(); 
    } 
} 
+0

Qu'advient-il si vous exécutez un shell différent? – dacwe

+0

@dacwe: Je ne pouvais faire fonctionner 'sh' que jusqu'à présent. J'ai essayé 'bash' mais il est arrêté en essayant de faire des E/S. Probablement il a besoin d'autres options ('+ m' n'aide pas). – vitaut

Répondre

1

Parce que l'erreur et la sortie standard vont à différents fils qui impriment les données lues de manière asynchrone. Cela peut fonctionner, si vous redirigez 2>&1, mais je ne suis pas sûr que cela fonctionnera avec Runtime.exec (peut provoquer "fichier introuvable - 2> & 1"). Ainsi, vous pouvez faire un script shell qui appelle sh et réoriente sa sortie, et appelez ce script en utilisant Runtime.exec:

#!/bin/sh 
sh -i +m 2>&1 

et

Runtime.exec("customsh"); 
+0

Mais '' '' 'et'/home/viz/workspace' devraient-ils tous les deux sortir sur la sortie standard? (donc pas de course là-bas ..) – dacwe

+0

@dacwe Non. Essayez à partir de la ligne de commande 'sh 1> temp.log', puis tapez' pwd'. Vous verrez l'invite de la ligne de commande mais pas la sortie de pwd, cela ira 'temp.log'. – khachik

+0

Nice! Ensuite, il y a une solution vitaut! – dacwe