使用Runtime.getRuntime()在Java中运行Windows命令.exec(String [])

时间:2014-09-25 17:07:52

标签: java windows command-line

我从java运行这个令人困惑的Windows命令时遇到了一些麻烦,我无法找到任何类似于我尝试做的基于我的代码的内容。< / p>

基本上,windows命令会杀死与套接字相关的任何PID,这些PID具有CLOSE_WAIT状态并且与指定的特定ip:端口相关。我的问题是我很难使用Runtime.getRuntime()。exec()来运行它。

String[] command = {"cmd /c for /f \"tokens=5\" %a in ('netstat -noa -p tcp ^| find /i \"CLOSE_WAIT\" ^| find /i \""+ip+":443\" ') do if not \"%a\"==\"0\" echo taskkill /pid %a"};     
Process runCommand = Runtime.getRuntime().exec(command);
runCommand.waitFor(); 

执行此操作时,我当前收到错误消息:

  

class java.io.IOException消息:无法运行程序&#34; C:/ cmd / c for   / f&#34;令牌= 5&#34; %a in(&#39; netstat -noa -p tcp ^ | find / i&#34; CLOSE_WAIT&#34; ^ |   找/我&#34; ip:443&#34; &#39;)如果不是&#34;%a&#34; ==&#34; 0&#34; echo taskkill / pid%a&#34;:   CreateProcess error = 2,系统找不到指定的文件

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:2)

通过传递String []数组而不是单个String,您告诉系统运行一个.exe文件,其名称包含大约144个字符,其中前13个是cmd /c for /f。显然,没有具有该名称的.exe文件。

您可以尝试的一件事是将单个String传递给exec(String)方法,而不是传递一个字符串数组。这可能会也可能不会起作用,因为Java会将您的字符串拆分为以空格分隔的单词,然后Windows将启发式地尝试找出您想要的内容。

另一种可行的方法是包含3个元素的String数组:

String[] command = { "cmd", "/c", "for /f \"tokens=5\" %a in ('netstat -noa -p tcp ^| find /i \"CLOSE_WAIT\" ^| find /i \""+ip+":443\" ') do if not \"%a\"==\"0\" echo taskkill /pid %a" };

在我看来,最好的办法是不依赖cmd.exe来解析命令行参数。我怀疑Java在处理文本方面至少同样有效:

Collection<String> pids = new ArrayList<>();

ProcessBuilder p = new ProcessBuilder("netstat.exe", "-noa", "-p", "tcp");
p.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE);
Process netstat = p.start();

try (BufferedReader output =
    new BufferedReader(new InputStreamReader(netstat.getOutputStream()))) {

    String line;
    while ((line = output.readLine()) != null) {

        if (line.toUpperCase().contains("CLOSE_WAIT") &&
            line.contains(ip + ":443")) {

            String[] tokens = line.split("\\s+");
            String pid = tokens[4];
            if (!pid.equals("0")) {
                pids.add(pid);
            }
        }
    }
}

if (netstat.waitFor() != 0) {
    throw new IOException("netstat command failed");
}

p.inheritIO();
for (String pid : pids) {
    Process taskkill = p.command("taskkill.exe", "/pid", pid).start();
    taskkill.waitFor();
}

如果您使用的是Java 8,您还可以使用Streams编写更类似于管道命令的代码:

ProcessBuilder p = new ProcessBuilder("netstat.exe", "-noa", "-p", "tcp");
p.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE);
Process netstat = p.start();

try (BufferedReader output =
    new BufferedReader(new InputStreamReader(netstat.getOutputStream()))) {

    final ProcessBuilder taskkill = new ProcessBuilder().inheritIO();

    output.lines()
        .filter(line -> line.toUpperCase().contains("CLOSE_WAIT") &&
            line.contains(ip + ":443"))
        .map(line -> line.split("\\s+")[4])
        .filter(pid -> !pid.equals("0"))
        .forEach(pid ->
            taskkill.command("taskkill.exe", "/pid", pid).start());
}

if (netstat.waitFor() != 0) {
    throw new IOException("netstat command failed");
}