2010-11-17 21 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已经完成,不再看到破裂的管道退出代码返回。