通过Runtime.getRuntime()。exec运行linux命令时出错

时间:2010-06-22 12:27:05

标签: java runtime.exec

我正在尝试在我的Java程序中运行以下命令

Runtime.getRuntime().exec("ls -lrt service/logs/post/level2.log | awk '{print $9}'");
or
Runtime.getRuntime().exec("ls -lrt service/logs/post/level2* | awk '{print $9}'");

它给了我以下错误

ls: 0653-341 The file | does not exist.
ls: 0653-341 The file awk does not exist.
ls: 0653-341 The file '{print does not exist.
ls: 0653-341 The file $9}' does not exist.

请帮助我

1 个答案:

答案 0 :(得分:9)

管道是基于shell的构造,而不是实际的可运行命令。我看到它有两种选择:

  1. 在Java中自己管道。首先调用ls命令,获取其OutputStream的句柄,然后调用awk将第一个Process的输出连接到第二个Process输入流
  2. 直接从Java调用bash shell,将整个命令作为参数传递给bash的-c参数。这样,所有管道都在 单个过程中完成。
  3. 对于基于令牌的错误,您应该使用字符串数组调用这些命令;每个元素代表命令行的标记。所以试试,例如:

    Runtime.getRuntime().exec(new String[] { "ls", "-lrt", "service/logs/post/level2.log" });
    

    以便调用ls命令。在这种情况下,我不认为这是严格必需的,但它将用于awk命令,因为Java不知道任何关于特定于shell的引用规则,所以默认情况下标记空格字符上的单字符串输入。这就是你的awk脚本分成两部分的原因。


    编辑(以回应评论):在第一个选项中,我的意思是你能够在Java中自己管理两个进程之间的输出。

    想象一下,如果你已经创建了一个过程:

    Process ls = Runtime.getRuntime().exec("ls -lrt service/logs/post/level2.log");
    

    现在,这个过程将运行并生成一些输出(我们知道它将是描述该文件的一行)。我们可以像这样得到这个输出的流:

    InputStream lsOut = ls.getInputStream();
    

    现在,我们想要运行awk进程:

    Process awk = Runtime.getRuntime().exec(new String[] { "awk", "{print $9}"});
    

    awk进程当然会坐在等待输入的那一刻,因为它知道它将从stdin读取。因此,我们抓住它将要使用的输入流:

    OutputStream awkIn = awk.getOutputStream();
    

    现在,管道位 - 我们读取ls命令的输出并将其传递给awk的输入:

    // TODO add buffering, error handling, probably run this in a separate thread
    int datum = lsOut.read();
    while (datum != -1)
    {
        awkIn.write(datum);
        datum = lsOut.read();
    }
    

    这会读取ls的输出(为了简单起见逐字节,使用字节数组缓冲区要快得多,但我试图简单地说明这个概念)并将其写入{{{}的输入。 1}}。

    然后,只需要阅读awk进程的输出并按照您认为合适的方式处理它。