【问题标题】:Get output of terminal multi-arg command using Java使用 Java 获取终端多参数命令的输出
【发布时间】:2020-09-30 12:13:54
【问题描述】:

我正在尝试从 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

我错过了什么?

【问题讨论】:

    标签: java terminal sox


    【解决方案1】:

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

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

    hello foo bar "baz boz" 转化为概念:应用名为hello,它有3 个参数foobarbaz boz那就是 bash。 Bash 执行“哦,引号,那些需要捆绑起来”。

    一般来说,不要使用单字符串版本。使用java.lang.ProcessBuilder

    另请注意,将bash 翻译成/bin/bash 也是一种贬义。

    最后,请注意,根据平台和月相,Runtime.exec 和朋友会做一些 bashisms。也许。问题是,它不可靠,所以不要依赖它(例如,在 Windows 上,*.txt 通常可以工作,而在所有非 Windows 操作系统上它几乎永远不会工作,并且 Runtime.exec 确实对 @ 进行了一些应用987654332@,但不一定像 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。

    【讨论】:

    • 我还尝试了 ProcessBuilder 与各种命令分离,并且没有成功的过时路径。但是此时我通过简单地运行“command1”(在主帖中提到)得到输出,但它被打印到 p.getErrorStream() 而不是 p.getInputStream()... 我将使用它作为解决方法。
    猜你喜欢
    • 2013-02-01
    • 2019-01-06
    • 2013-09-06
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多