Question

Je suis sous l'impression que les processus du système d'exploitation ont trois flux standards: stdin, stdout, and stderr. Je pense également que les éditeurs de texte, comme le travail en prenant vim entrée sur stdin et envoyer des caractères d'échappement ANSI sur stdout. Cependant, mon point de vue de la façon dont les interprètes de ligne de commande ne tient pas dans ce seul cas:

Quand je lance la commande C:\cygwin\bin\bash.exe, je suis invité à:

Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\masson>C:\cygwin\bin\bash.exe
bash-3.2$ 

... mais quand je le lance en Java avec l'extrait suivant, le flux stdin est vide:

ProcessBuilder pb = new ProcessBuilder("C:\\cygwin\\bin\\bash.exe");
pb.redirectErrorStream(true);
Process proc = pb.start();
final InputStream in = proc.getInputStream();

new Thread(new Runnable() {
  public void run() {
    // Blocks forever...
    in.read(new byte[1024]);
  }
}).start();

Qu'est-ce qui se passe ici? On m'a dit que bash.exe est en cours d'exécution en mode interactif. Est-ce que cela signifie les flux standards ne sont pas utilisés? Comment puis-je travailler encore travailler avec ces programmes, et en fin de compte, comment pourrais-je mettre en œuvre ma propre version de cmd.exe? Je pense que je suis quelque chose de ne pas comprendre sur la façon dont les interprètes fondamental de ligne de commande fonctionnent ...

(Les liens vers d'articles traitant de sujets connexes serait très apprécié. Je ne l'ai pas eu la recherche beaucoup de chance. Oh, et une dernière question, sont des flux standards traités différemment dans Windows que dans la plupart des Unix systèmes d'exploitation? )

Était-ce utile?

La solution

Être en mode interactif ne signifie pas que les flux standards ne sont pas utilisés. Mais dans ce cas, Bash est le plus courant probable dans non Mode -interactive (il détecte qu'il ne parle pas directement à l'application du terminal, il suppose qu'il est utilisé par programme, et donc ne pas imprimer la bienvenue bannière). Dans ce cas, les flux standards sont encore utilisés, il est juste que rien n'est sortie.

en pointe ergosys Comme, vous ne pouvez pas vraiment compter sur in.read(new byte[1024]) retour avant qu'il ait lu les pleins 1024 octets, mais il est probablement correct de supposer qu'il - cependant, il ne sera certainement pas revenir avant qu'il ne soit lu au moins un octet, et je pense que le problème est ici - vous n'obtenez même un octet de sortie

.

Essayez de passer "-i" à bash pour le faire fonctionner en mode interactif.

Autres conseils

Tout programme utilisant la bibliothèque standard c peut dire si elle parle à un dispositif TTY (a.k.a ligne de commande) en utilisant la fonction isatty (). Bash détecte sans doute qu'il parle à un tuyau au lieu d'un téléscripteur et ne délivre pas une invite.

Je suis plus un gars Python qu'un gars Java (donc tout ce que je vous dis est rapide de suppositions JavaDoc), mais il semble que vous configurez un blocage multi-processus.

in.read(new byte[1024]); ne reviendra pas jusqu'à ce qu'il soit lu 1024 octets de données et bash.exe ne délivre pas un 1024 octets entiers avant d'arrêter d'attendre l'entrée. (Pour ce faire, utilisez proc.getOutputStream() et nourrir quelques commandes pour répondre.)

Par conséquent, vous obtenez Java en attente de bash pour répondre et bash en attente de Java pour répondre et à la fois le contenu tout à fait d'attendre jusqu'à ce que la mort de l'univers sans s'ennuyer ou fatigué.

Mon conseil est d'utiliser in.available() avant chaque appel à in.read() pour éviter le blocage. De cette façon, vous pouvez basculer entre les données et l'alimentation en le tirant sans se coincer.

En fait, ce serait probablement beaucoup plus simple et plus sain juste envelopper dans un BufferedReader .

Mise à jour du commentaire: En outre, lorsque des outils tels que bash détectent stdin n'est pas un terminal (voir l'appel système isatty), ils tampon en morceaux énorme (4K ou plus) en supposant que l'entrée est non-interactif. Je ne sais pas si ça va aider, mais essayez de démarrer bash avec le drapeau -i.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top