首先,我建議更換這條線路。Process?process?=?Runtime.getRuntime?().exec?("/bin/bash");
帶著線條ProcessBuilder?builder?=?new?ProcessBuilder("/bin/bash");builder.redirectErrorStream(true);Process?process?=?builder.start();
ProcessBuilder是Java 5中的新版本,使運行外部進程更容易。在我看來,它比Runtime.getRuntime().exec()它允許您將子進程的標準錯誤重定向到其標準輸出中。這意味著你只有一個InputStream讀。在此之前,您需要有兩個單獨的線程,一個從stdout從stderr,以避免在標準輸出緩沖區為空(導致子進程掛起)時填充標準錯誤緩沖區,反之亦然。
接下來,循環(其中有兩個)while?((line?=?reader.readLine?())?!=?null)?{
System.out.println?("Stdout:?"?+?line);}
只有在reader,它從進程的標準輸出中讀取,返回文件結束。只有當bash進程退出。如果目前沒有進程的輸出,它將不會返回文件末尾。相反,它將等待進程的下一行輸出,直到有了下一行才返回。
由于在到達此循環之前,您要向進程發送兩行輸入,如果在這兩行輸入之后進程尚未退出,則這兩個循環中的第一個循環將掛起。它將坐在那里等待另一行被閱讀,但它將永遠不會有另一行可讀。
我編譯了你的源代碼(我現在Windows上,所以我替換了/bin/bash帶著cmd.exe,但原則應該是相同的),我發現:輸入兩行后,出現前兩個命令的輸出,但是程序掛起,
如果我打字,比如說,
echo test,然后
exit,程序退出了第一個循環,因為
cmd.exe進程已經結束。然后,程序請求另一行輸入(被忽略),直接跳過第二個循環,因為子進程已經退出,然后退出。
如果我輸入
exit然后
echo test,我收到一個IOException抱怨管道被關閉。這是意料之中的-第一行輸入導致進程退出,沒有地方發送第二行。
我在我曾經做過的一個程序中,看到了一個類似于你想要的東西的把戲。這個程序保存了許多shell,在其中運行命令并讀取這些命令的輸出。使用的技巧是始終寫出一個“魔術”行,標記shell命令的輸出結束,并使用它來確定發送到shell的命令的輸出何時完成。
我取下了您的代碼,在分配給您的行之后,我替換了所有的代碼。writer使用以下循環:while?(scan.hasNext())?{
String?input?=?scan.nextLine();
if?(input.trim().equals("exit"))?{
//?Putting?'exit'?amongst?the?echo?--EOF--s?below?doesn't?work.
writer.write("exit\n");
}?else?{
writer.write("(("?+?input?+?")?&&?echo?--EOF--)?||?echo?--EOF--\n");
}
writer.flush();
line?=?reader.readLine();
while?(line?!=?null?&&?!?line.trim().equals("--EOF--"))?{
System.out.println?("Stdout:?"?+?line);
line?=?reader.readLine();
}
if?(line?==?null)?{
break;
}}
完成此操作后,我可以可靠地運行幾個命令,并將每個命令的輸出分別返回給我。
兩人echo --EOF--發送到shell的行中的命令,以確保命令的輸出以--EOF--即使在命令錯誤的結果中。
當然,這種方法也有其局限性。這些限制包括:如果輸入一個等待用戶輸入的命令(例如,另一個shell),則程序似乎掛起,
它假設shell運行的每個進程都以換行符結束其輸出,
如果shell運行的命令恰好寫出一行,就會有點混亂。
--EOF--.
bash如果輸入不匹配的文本,則報告語法錯誤并退出。
).
這些點對你來說可能并不重要,如果你想把它當作一個預定的任務來運行,那么它將被限制在一條命令或一小部分命令上,而這些命令永遠不會以這種病態的方式運行。
編輯:在Linux上運行此程序后,改進退出處理和其他小的更改。