java 命令执行转义 '|'

java command execution escapes '|'

我有执行系统命令的功能:

public String cmd(String s) {
    String out = "";
    try {
        Runtime run = Runtime.getRuntime();
        Process pr = run.exec(s.split(" "));
        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line = "";
        while ((line=buf.readLine())!=null) {
            out+=line+"\n";
        }
    } catch(Exception e) {
        e.printStackTrace();
    }
    return out;
}

命令经过:

cmd("nmap -sL -n 192.168.1.0/24 | awk '/Nmap scan report/{print $NF}'");

预期输出:

192.168.1.0
192.168.1.1
 ...

实际输出:

Starting Nmap 7.80 ( https://nmap.org ) at 2021-04-12 20:27 EET
Nmap scan report for 192.168.1.0 ...

管道由 shell 解释。它执行一个命令,然后将一个命令的输出传递给下一个命令。您可以在 Java 中模拟此操作,启动两个命令,然后将第一个程序的 OutputStream 泵送到第二个程序的 InputStream

或者,如果您不想这样做,您仍然可以调用类似“sh -c 'command1 | command2”的命令

类似的问题回答得很好:

  • Using Java ProcessBuilder to Execute a Piped Command

To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.

Process p = new ProcessBuilder().command("bash", "-c", command).start();

bash invokes a shell to execute your command and -c means commands are read from string. So, you don't have to send the command as an array in ProcessBuilder.

适合您的情况

String cmd(String command) {
  ProcessBuilder builder = new ProcessBuilder();
  builder.redirectErrorStream(true); // add stdErr to output

  Process process = builder.command("bash", "-c", command).start();
    
  StringBuilder processOutput = new StringBuilder(); // add lines easier
  // try-with to auto-close resources
  try (BufferedReader processOutputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));) {
    String readLine;
    while ((readLine = processOutputReader.readLine()) != null) {
      processOutput.append(readLine + System.lineSeparator()); // use system's line-break
    }

    process.waitFor();
  }

  return processOutput.toString().trim();
}

然后按预期调用:

cmd("nmap -sL -n 192.168.1.0/24 | awk '/Nmap scan report/{print $NF}'");

注意:我把它增强了一点

灵感来自: read the output from java exec