代码之家  ›  专栏  ›  技术社区  ›  Will

从java调用脚本,接收到sigpipe信号

  •  3
  • Will  · 技术社区  · 14 年前

    在从Java进程调用shell脚本时,我遇到了一些奇怪的行为。

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

    StreamGobblerThread只有一个run()方法,它执行

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

    大约有20%的时间是这样的,但是大部分脚本都失败了,返回代码是141。

    从我在google上找到的,141是接收到SIGPIPE时的返回代码。

    有什么想法吗?

    4 回复  |  直到 14 年前
        1
  •  2
  •   Reverend Gonzo    14 年前

    我不是百分之百确定是什么问题,但首先:

    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);
    }
    

    read()正在阻塞,因此,这样它实际上将继续读取,直到流正确关闭。

    (注意:这段代码来自Groovy的consumerprocessoutput()实现)

        2
  •  1
  •   user500944user500944    14 年前

    这可能意味着“管道破裂”错误。当管道连接的一个进程在另一个管道之前退出时,可能会发生这种情况。

        3
  •  1
  •   AlexR    14 年前

    我一生中见过好几次,找到了两个解决办法。

    1. 如果您真的想分别读取错误和输出流,请运行如下命令 “/bin/sh foo.sh 1>/tmp/out 2>/tmp/err”,然后读取这些文件。
    2. 如果您可以阅读stdout和stderr的混合物,请使用ProcessBuilder,如下所示:

    ProcessBuilder b=新的ProcessBuilder(“foo.sh”); b、 重定向错误流(真); 进程p=b.start(); p、 getInputStream(); //..... 等。

    现在从同时包含stdout和stderr的输入流中读取。

        4
  •  0
  •   Dan675    10 年前

    我有一个类似的问题,在一个线程中执行进程,这个线程的run方法会读取进程InputStream,然后调用waitFor()方法。

    正如OP所做的那样,我将进程的读取移动到自己的线程中,不再看到中断的管道出口代码返回。