ProcessBuilder getOutputStream en interactie met processen

Ik heb problemen met de interactie met een proces met behulp van getOutputStream. Hier is mijn code:

    Process p = null;
    ProcessBuilder pb = new ProcessBuilder("/home/eric/this.sh");
    pb.directory(new File("/home/eric/"));
    p = pb.start();

    InputStream in = null;
    OutputStream outS = null;

    StringBuffer commandResult = new StringBuffer();
    String line = null;
    int readInt;

    int returnVal = p.waitFor();

    in = p.getInputStream();

    while ((readInt = in.read()) != -1)
        commandResult.append((char)readInt);
    outS = (BufferedOutputStream) p.getOutputStream();
    outS.write("Y".getBytes());
    outS.close();

    System.out.println(commandResult.toString());
    in.close();

Dit is de uitvoer:

Reading package lists...
Building dependency tree...
Reading state information...
The following packages were automatically installed and are no longer required:
  libmono2.0-cil libmono-data-tds2.0-cil libmono-system-data2.0-cil
  libdbus-glib1.0-cil librsvg2-2.18-cil libvncserver0 libsqlite0
  libmono-messaging2.0-cil libmono-system-messaging2.0-cil
  libmono-system-data-linq2.0-cil libmono-sqlite2.0-cil
  libmono-system-web2.0-cil libwnck2.20-cil libgnome-keyring1.0-cil
  libdbus1.0-cil libmono-wcf3.0-cil libgdiplus libgnomedesktop2.20-cil
Use 'apt-get autoremove' to remove them.
The following extra packages will be installed:
  firefox-globalmenu
Suggested packages:
  firefox-gnome-support firefox-kde-support latex-xft-fonts
The following NEW packages will be installed:
  firefox firefox-globalmenu
0 upgraded, 2 newly installed, 0 to remove and 5 not upgraded.
Need to get 15.2 MB of archives.
After this operation, 30.6 MB of additional disk space will be used.
Do you want to continue [Y/n]? Abort

this.sh voert gewoon "gksudo apt-get install firefox" uit

Ik weet niet waarom het is het afbreken en het niet nemen van mijn input "Y" bedankt.

3
Ik kan dat naar het einde verplaatsen, het verandert het gedrag niet. Het punt is dat het afbreekt voordat het ooit mijn OutputStream bereikt.
toegevoegd de auteur Eric, de bron
Dat is eigenlijk niet mijn probleem, het heeft iets te maken met gksudo waardoor het wordt afgebroken voordat op gebruikersinvoer wordt gewacht. Het gedraagt ​​zich hetzelfde wanneer het rechtstreeks vanaf de opdrachtregel wordt uitgevoerd. Maar het was absoluut een probleem.
toegevoegd de auteur Eric, de bron
@Roger, je zou je laatste commentaar moeten omzetten in een antwoord. Dat is zeker zijn probleem.
toegevoegd de auteur Gray, de bron
+1 voor goed geschreven vraag met code en uitvoer.
toegevoegd de auteur Gray, de bron
Ik denk echt niet dat je de stream moet sluiten zodra je een "Y" hebt verzonden.
toegevoegd de auteur Roger Lindsjö, de bron
Er is iets gemist tijdens het lezen van de eerste keer. Voordat u de invoer- en uitvoerstromen ontvangt, begint u met p.waitFor (). Volgens de javadoc wacht dit totdat het proces sterft. Is dit wat je wilt? Het verzenden van een 'Y' nadat het stierf lijkt zinloos.
toegevoegd de auteur Roger Lindsjö, de bron

1 antwoord

Er zijn verschillende problemen.

First: gksudo(1) does some dirty, non-standard tricks with the standard input and standard output of the commands it starts. It fails horrible. A good example is this command line:

$ echo foo | gksudo -g cat

Ik zou elke uitvoer en beëindiging van de cat verwachten zodra de echo de gegevens heeft afgeleverd. Nee. Zowel gksudo en cat blijven voor altijd hangen. Geen uitvoer.

Je usecase zou zijn

echo y |gksudo apt-get install ....

en dit zal ook niet werken. Zolang dit niet is opgelost, kunt u vergeten om een ​​afstandsbediening te doen als het gestarte programma enige gebruikersinvoer vereist.

Second: As already pointed out by Roger waitFor() waits for the termination of the command. This will not happen any time soon without any user input and with the gksudo problem.

Third After shoving waitFor down a bit there is the next blocker: You wait for the complete output of the process up to and including the EOF. This will not happen anytime soon (see "first" and "second").

Fourth Only after the process is already dead twice (see "second" and "third") it might get some input - your Y (which might also need an additional \n).


In plaats van dit probleem op te lossen, kan er een betere en veel gemakkelijkere manier zijn: probeer apt-get install niet te besturen met standaardinvoer. Geef het gewoon een aantal geschikte opties die uw vragen automatisch "beantwoorden". Een snelle man apt-get laat een aantal kandidaten zien:

-y, --yes, --assume-yes
--force-yes
--trivial-only
--no-remove
--no-upgrade

Raadpleeg de handleiding voor details.

Ik denk dat dit de betere en stabielere manier is.

PS: Op dit moment ben ik nogal een beetje ***, dus excuseer het gezeur hierboven.

1
toegevoegd
Ik ben het met je eens op gksudo, dus ik heb genoten van de tirade. Heel erg bedankt voor je hulp
toegevoegd de auteur Eric, de bron