2010-11-17 43 views
3

從Java進程調用shell腳本時遇到一些奇怪的行爲。從java調用腳本,接收到sigpipe信號

Process p = Runtime.getRuntime().exec("mybashscript.sh"); 
(new StreamGobblerThread(p.getInputStream())).start(); 
(new StreamGobblerThread(p.getErrorStream())).start(); 
p.waitFor(); 
returnValue = p.exitValue(); 

的StreamGobblerThread只是有,做了

while(((inputStream.available>0) { inputStream.skip(available); } 

大約有20%的這部作品時的run()方法,但大多腳本失敗,141返回碼的時候了。

從我在google上發現的,141是收到SIGPIPE時的返回碼。

任何想法?

+0

也許你應該打印出的錯誤,他們可能會給你一個有意義的錯誤信息 – 2010-11-17 20:39:04

+0

'SIGPIPE'可能是由'while'提前退出引起的'StreamGobblerThread'。要檢查它,只需使用空的'run()'。在循環中添加一些調試打印以查看「可用」是什麼。嘗試讀取數據而不是跳過。 – khachik 2010-11-17 20:45:48

+0

除了腳本的返回代碼之外,似乎沒有'錯誤',因爲它不是發生的java異常。所有java似乎知道的是腳本的退出代碼 – Will 2010-11-17 20:49:00

回答

2

我不是100%確定是什麼問題,但首先:

while(((inputStream.available>0) { inputStream.skip(available); } 

無效。

這是因爲inputStream.available()沒有被阻塞,所以如果它沒有任何要立即讀取的東西,它根本不會讀取任何東西。

你最好不要有這樣的事:

byte[] buf = new byte[8192]; 
int next; 
try { 
    while ((next = in.read(buf)) != -1) {} 
} catch (IOException e) { 
    throw new GroovyRuntimeException("exception while dumping process stream", e); 
} 

閱讀()是阻塞的話,這樣實際上會繼續讀書,直到流被正常關閉。

(注:此代碼是Groovy的實現consumeProcessOutput的()

+0

好抓住.. StreamGobbler線程實際上關閉inputStream只要沒有更多的可用。但由於shell腳本可能仍在運行,它會過早關閉它。 – Will 2010-11-17 23:17:58

1

這可能意味着一個「破管」錯誤。當管道連接的其中一個進程在另一個進程之前退出時,可能會發生這種情況。

1

我在我的生活中看過幾次,發現了兩種解決方法。

  1. 如果你真的想分開讀取錯誤和輸出流,運行命令一樣 「/ bin/sh的foo.sh 1>的/ tmp /出2>的/ tmp/ERR」,然後從這些文件中讀取。
  2. 如果它是很好的爲你讀輸出和錯誤的混合物,使用的ProcessBuilder如下:

的ProcessBuilder B =新的ProcessBuilder( 「foo.sh」); b.redirectErrorStream(true); 進程p = b.start(); p.getInputStream(); // .....等

現在從包含stdout和stderr的輸入流中讀取。

0

我在執行的過程中誰的run方法會讀取過程的InputStream,然後調用WAITFOR()方法的線程類似的問題。

我感動的過程中閱讀的InputStream到它自己的線程作爲OP已經完成,不再看到破裂的管道退出代碼返回。