用java执行脚本,读取错误和输出流
我希望能够从java执行一个外部命令,例如“ls”,并以字符串的形式实时获取输出,包括输出流和错误流,并且按照它们生成的顺序 因此,如果命令的输出类似于:用java执行脚本,读取错误和输出流,java,shell,Java,Shell,我希望能够从java执行一个外部命令,例如“ls”,并以字符串的形式实时获取输出,包括输出流和错误流,并且按照它们生成的顺序 因此,如果命令的输出类似于: blah <- to stdout foo <- to stderr bar <- to stdout 朴素的方法会产生以下结果之一: blah bar (即无标准输出) 或: (即重新排列顺序,使stdout和stderr消息不会相互交错)。使用ProcessBuilder并设置redire
blah <- to stdout
foo <- to stderr
bar <- to stdout
朴素的方法会产生以下结果之一:
blah
bar
(即无标准输出)
或:
(即重新排列顺序,使stdout和stderr消息不会相互交错)。使用
ProcessBuilder
并设置redirectErrorStream(true)
使用ProcessBuilder
并设置redirectErrorStream(true)
这并非总是可能的
如果使用ProcessBuilder
API,可以将stdout
和stderr
流合并为一个流(使用redirectErrorStream(true)
),因此可以在一个InputStream
中读取两个输出。但这意味着您无法区分数据最初来自哪个流
如果将stdout
和stderr
读作两个流,则需要NIO或两个Java线程。在这两种情况下,处理一个输出会阻塞另一个输出(或者说,另一个流不会被及时处理)。这将导致交换线路
如果子进程不刷新输出,而您使用管道,则情况会变得更糟,因为stdout
将以4KB块的形式发送到您的进程,而stderr
通常会逐行到达
恐怕没有独立于平台的解决方案。如果您只需要一个在Unix上工作的解决方案,那么可以使用Pseudo TTYs()来模拟shell,但这些都很难从Java中设置,因为您需要调用OS函数
一种方法可能是使用Perl或类似工具在PTY中运行命令(这会导致stdout变成行缓冲),从那里读取stdout和stderr,并在每行前面加上stdout的
1
,stderr的2
。这并不总是可能的
如果使用ProcessBuilder
API,可以将stdout
和stderr
流合并为一个流(使用redirectErrorStream(true)
),因此可以在一个InputStream
中读取两个输出。但这意味着您无法区分数据最初来自哪个流
如果将stdout
和stderr
读作两个流,则需要NIO或两个Java线程。在这两种情况下,处理一个输出会阻塞另一个输出(或者说,另一个流不会被及时处理)。这将导致交换线路
如果子进程不刷新输出,而您使用管道,则情况会变得更糟,因为stdout
将以4KB块的形式发送到您的进程,而stderr
通常会逐行到达
恐怕没有独立于平台的解决方案。如果您只需要一个在Unix上工作的解决方案,那么可以使用Pseudo TTYs()来模拟shell,但这些都很难从Java中设置,因为您需要调用OS函数
一种方法可能是使用Perl或类似工具在PTY中运行命令(这会导致stdout变成行缓冲),从那里读取stdout和stderr,并在每一行前面加上stdout的
1
,stderr的2
。我建议您使用它们,因为它们是更复杂的API
请参阅:您可以:
- 为子流程设置当前工作目录
- 提供一组传递给子流程的环境变量
- 使用ExecuteStreamHandler捕获stdout和stderr的子流程输出
- 使用ExecuteWatchLog终止长时间运行的进程
- 定义一组预期的退出值
- 当主进程使用ProcessDestroyer终止时,终止任何已启动的进程
- 为子流程设置当前工作目录
- 提供一组传递给子流程的环境变量
- 使用ExecuteStreamHandler捕获stdout和stderr的子流程输出
- 使用ExecuteWatchLog终止长时间运行的进程
- 定义一组预期的退出值
- 当主进程使用ProcessDestroyer终止时,终止任何已启动的进程
- 我建议您使用,因为它们是更复杂的API
请参阅:您可以:
blah
bar
blah
bar
foo