管道是基于 shell 的构造,而不是实际的可运行命令。在我看来,有两种选择:
- 在 Java 中自己做管道。首先调用
ls
命令,获取其句柄OutputStream
,然后调用awk
将第一个Process
' 的输出连接到第二个Process
' 输入流。
- 直接从 Java 调用 bash shell,将整个命令作为参数传递给 bash 的
-c
参数。这样,所有管道都在单个过程中完成。
至于基于令牌的错误,您应该使用字符串数组调用这些命令;每个元素代表命令行的一个标记。所以试试,例如:
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 进程当然会在等待输入的那一刻坐在那里,因为它知道它将从标准输入读取。因此,我们获取将要使用的输入流:
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
(为简单起见,逐字节读取,使用字节数组缓冲区会快得多,但我试图简单地说明这个概念)并将其写入awk
.
然后,只需读取awk
流程的输出并按照您认为合适的方式处理它。