Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 未执行Shell命令_Java_Bash_Shell - Fatal编程技术网

Java 未执行Shell命令

Java 未执行Shell命令,java,bash,shell,Java,Bash,Shell,我在java程序中执行shell命令时遇到了一个奇怪的问题。因为有成千上万的网站解释如何做,我使用了以下推荐代码: public String executeShellCommand (String command) { try { StringBuffer sb = new StringBuffer(); String line = ""; Process p = Runtime.getRuntime().exec(comman

我在java程序中执行shell命令时遇到了一个奇怪的问题。因为有成千上万的网站解释如何做,我使用了以下推荐代码:

public String executeShellCommand (String command)
{
    try
    {
        StringBuffer sb = new StringBuffer();
        String line = "";

        Process p = Runtime.getRuntime().exec(command);
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                p.getInputStream()));
        while ((line = reader.readLine()) != null)
            sb.append(line + "\n");
        p.waitFor();

        return sb.toString();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}
实际上,当我尝试执行例如
ls-aF
时,效果很好,因此我得到了一些输出。因此,我非常确定上述代码在原则上是正确的。然而,我有另一个程序,我想运行,并产生一个文件作为输出。我想以上面的方式执行它,但它从未执行过,也没有生成输出文件。此外,我没有在java中得到任何错误、警告或任何东西。将实际的
命令
参数字符串复制并粘贴到控制台时,直接在shell中执行程序/命令效果良好,并生成输出文件。因此,我传递给该方法的命令也是正确的

在java中执行shell命令时,是否还有其他需要注意的事项

更新:我根据建议修改了代码。然而,它仍然悬而未决:

    public String executeShellCommand(List<String> command, String logfile, boolean waitForProcess) { try {
    ProcessBuilder pb = new ProcessBuilder(command);
    System.out.println("pb.toString() = " + pb.toString());
    Process p = pb.start();
    System.out.println("2");
    BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
    System.out.println("3");
    StringBuilder errSb = new StringBuilder();
    StringBuilder outSb = new StringBuilder();
    String line;
    System.out.println("4");
    while ((line = err.readLine()) != null) { // <--- code hangs here
        errSb.append(line + "\n");
        System.out.println("errSb = " + errSb.toString());
    }
    System.out.println("4a");
    while ((line = out.readLine()) != null) { 
        outSb.append(line + "\n");
        System.out.println("outSb = " + outSb.toString());
    }

    System.out.println("5");

    if(waitForProcess) {
        System.out.println("Wait for process");
        p.waitFor();
    } else {
        System.out.println("Sleep 5000");
        Thread.sleep(5000);
    }
    System.out.println("6");
    //Log result to file
    if(logfile != null) {
        OutputStreamWriter outWriter = new OutputStreamWriter(new FileOutputStream(logfile));
        outWriter.write(errSb.toString());
        outWriter.close();
    }
    return errSb.toString();
} catch(Exception e) { e.printStackTrace(); } return null; }
publicstringexecuteshellcommand(List命令、stringlogfile、booleanwaitforprocess){try{
ProcessBuilder pb=新的ProcessBuilder(命令);
System.out.println(“pb.toString()=”+pb.toString());
进程p=pb.start();
系统输出打印项次(“2”);
BufferedReader err=新的BufferedReader(新的InputStreamReader(p.getErrorStream());
BufferedReader out=新的BufferedReader(新的InputStreamReader(p.getInputStream());
系统输出打印项次(“3”);
StringBuilder errSb=新的StringBuilder();
StringBuilder outSb=新的StringBuilder();
弦线;
系统输出打印项次(“4”);

而((line=err.readLine())!=null){/如果您的命令向stderr写入太多字符,这将阻塞。与sdtout一样,Java通过管道重定向stderr,如果您不读取管道,它可能会填充并阻塞(管道的大小可能小于256字节)。为了避免这种情况,您需要从进程中读取。getErrorStream(),最好是从另一个线程读取,因为主线程正忙于从进程读取。getInputStream()

避免这种情况的一种更简单的方法是使用ProcessBuilder类,而不是Runtime.exec()和ProcessBuilder.redirectErrorStream(true),以便将stdout和stderr合并到Process.getInputStream()中,如下所示:

由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此未能及时写入子流程的输入流或读取子流程的输出流可能会导致子流程阻塞,甚至死锁

您正在调用
p.waitFor()
。如果我们仔细阅读:

如有必要,使当前线程等待,直到此进程对象表示的进程终止

您正在等待挂起的进程,因为它的错误流和输出流从未被读取

您应该做的是阅读这些流:

p.start();

BufferedReader err= new BufferedReader(new InputStreamReader(p.getErrorStream()));
BufferedReader out = new BufferedReader(new InputStreamReader(p.getOutputStream()));

StringBuilder errSb = new StringBuilder();
StringBuilder outSb = new Stringbuilder();

String line;
while ((line = err.readLine()) != null) {
    errSb.append(line);
}

while ((line = out.readLine()) != null) {
    outSB.append(line);
}

int retCode = p.waitFor(); //0 for success
System.out.println(retCode);
System.err.println(errSB.toString());
通过
进程
类调用外部程序时,您应该始终读取错误流,否则您可能会发现自己处于一个进程永远挂起的奇怪情况下(更确切地说,直到其他人(操作系统、另一个应用程序等)将其杀死)


我还注意到您使用了
Runtime.getRuntime()
,这不是运行外部程序的推荐方式,从java 1.5开始,如下所示:

从1.5开始,ProcessBuilder.start()是创建流程的首选方法


请尝试写出错误流并打印出进程的退出值。这并不能解决我的问题。它仍然挂起。请参阅我的更新。您试图运行的命令到底是什么?如果它必须从输入流中读取某些内容,而您不向输入流馈送,将再次导致挂起。does
while((line=err.readLine())!=null){errSb.append(line+“\n”);System.out.println(“errSb=“+errSb.toString());}
在控制台中打印任何内容?不,它正好挂起:
err.readLine()
。我的命令启动了一个守护进程。在取消对readline stuff的注释时,命令get exectues不会出现任何问题。我猜您的命令启动了一个写入文件的守护进程??如果是这样,读取err/out streams绝对没有意义。如果没有,请更新您的问题,并提供有关您所使用的命令的详细信息'我们正在尝试运行,您期望的输出,它的当前状态,观察到的异常行为,等等。不,它会将输出打印到stderr。我用python编写了一个脚本,其中所有内容都运行得非常好。只是这个java垃圾不起作用。我不知道该命令会如何影响java的执行。
ProcessBuilder pb = new ProcessBuilder("ls" , "-aF");
Process p = pb.start();