首页 > 解决方案 > 使用 Java 获取终端多参数命令的输出

问题描述

我正在尝试从 shell 命令解析 java 中的输出:(可以从 apt 安装 sox)

sox inputfile.flac -n stat

但我不能,几个小时的搜索,一无所获。

代码:

Process p = Runtime.getRuntime().exec(command);  
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));  

String line = null;
while ((line = in.readLine()) != null) {  
    System.out.println(line);  
} 

我尝试使用命令:

String command1 = "sox inputfile.flac -n stat";   //no output
String command2 = "bash -c sox inputfile.flac -n stat";   //output of 'sox' without arguments
String command3 = "sh -c sox inputfile.flac -n stat";   //output of 'sox' without arguments
String command4 = "sh -c \"sox inputfile.flac -n stat\"";   //error
String command5 = "bash -c \"sox inputfile.flac -n stat\"";   //error

根据文档 od 'sh':

-c 选项导致从字符串操作数而不是标准输入中读取命令。请记住,此选项仅接受单个字符串作为其参数,因此必须引用多字字符串。

所以我尝试了“command4”/“command5”->错误代码2。但是,我检查了普通的linux终端并且它工作正常:

sh -c "sox inputfile.flac -n stat"
bash -c "sox inputfile.flac -n stat"
sox inputfile.flac -n stat

我错过了什么?

标签: javaterminalsox

解决方案


您缺少的是 Process/Runtime 不是 bash。Bash 在实际运行之前对命令行执行操作。您不能在 ProcessBuilder 和朋友(Runtime.exec、Process 和 ProcessBuilder)中做这些事情。

变成*.txt所有文件的列表?那是巴什。

转入hello foo bar "baz boz"概念:应用程序被调用hello,它得到 3 个参数,, foo,barbaz boz? 那是 bash。Bash 执行“哦,引号,那些需要捆绑起来”。

作为一般规则,不要使用单字符串版本。使用java.lang.ProcessBuilder.

另请注意,翻译bash/bin/bash也是一种bashism。

最后,请注意,根据平台和月相,Runtime.exec 和朋友会做一些 bashisms。也许。问题是,它不可靠,所以不要依赖它(例如,在 Windows 上,*.txt通常可以工作,而在所有非 Windows 操作系统上它几乎永远不会,并且 Runtime.exec 确实做了一些应用程序$PATH,但不一定以与 bash 相同的方式)。

// Always absolute-path your executables.
// Always pass args separately.
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "sox inputfile.flac -n stat");
Process p = pb.start();

请注意,第二个字符串(带有 的字符串sox...)被传递给 bash。因此,如果您想在其中使用字符串转义符和星星,请随意。Bash 将处理它,而不是 ProcessBuilder:

// This won't work:
ProcessBuilder pb = new ProcessBuilder("ls", "*.txt");

// but this will:
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "ls *.txt");

*) 这是相当普遍的说法,但在我说“bashism”的地方,请随意插入您选择的外壳或“shellism”。关键是,它是一个外壳程序,它接收您在命令行上键入的内容并在将其实际传递给操作系统之前对其进行处理。Runtime.exec 和 co 也需要做这个处理;它的处理更加有限,您应该尽可能避免它:绝对路径,并单独列出 args。


推荐阅读