【问题标题】:How to use Process Builder in java to run Linux shell command?如何在 java 中使用 Process Builder 来运行 Linux shell 命令?
【发布时间】:2017-11-22 02:38:55
【问题描述】:

我正在尝试使用 JAVA 程序执行两个 linux 命令:

  1. ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1

这个命令给了我和“IP地址”,我必须在第二个命令中阅读和使用它

  1. ./executeTest.sh "IP 地址"

我用来运行这些命令的函数是这样的:

public int exec(String[] command, Map<String, String> envt, StringBuilder stdout, StringBuilder stderr, int timeoutSeconds) throws TimeoutException, Exception{
        int exitValue = -1;
        final File stdoutFile = File.createTempFile("test_", "extproc.out");
        final File stderrFile = File.createTempFile("test_", "extproc.err");
        Process process = null;
        try{    
            ProcessBuilder pb = new ProcessBuilder(command);
            if(envt!=null){
                for(Entry<String, String> entry : envt.entrySet()){
                    pb.environment().put(entry.getKey(), entry.getValue());
                }
            }
            pb.redirectOutput(stdoutFile);
            pb.redirectError(stderrFile);

            process = pb.start();

            boolean timedOut = false;

            timedOut = !(process.waitFor(timeoutSeconds, TimeUnit.SECONDS));

            if(timedOut){
                System.out.println("Timed out waiting for process to complete.");
                try{    
                    process.destroyForcibly();
                }catch(Exception killEx){
                    System.out.println("Error while terminating runaway process"+ killEx);
                }   
            }else{
                exitValue = process.exitValue();    
            }

            stdout.append(FileUtils.readFileToString(stdoutFile));
            stderr.append(FileUtils.readFileToString(stderrFile));

            if(timedOut){
                throw new TimeoutException();
            }
        }finally{
            if(stdoutFile.exists()){
                //File.deleteDirectory(stdoutFile);
            }
            if(stderrFile.exists()){
                //FileUtils.deleteDirectory(stdoutFile);
            }
            if(process != null){
                process.destroy();
            }

        }
        return exitValue;
    }

但是,当我为上面编写的两个命令调用此函数时,出现以下错误:

java.io.IOException: Cannot run program "ifconfig | grep -A 1 'eth0' | tail -1 |cut -d ':' -f 2 |cut -d ' ' -f 1": error=2, No such file or directory
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
        at IOxUnifiedSanityTestSuite.starWebServer.exec(starWebServer.java:66)
        at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:148)
        at IOxUnifiedSanityTestSuite.starWebServer$2.handle(starWebServer.java:124)
        at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:217)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:133)
        at io.vertx.ext.web.impl.RouterImpl.accept(RouterImpl.java:79)
        at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:288)
        at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:421)
        at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:134)
        at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:623)
        at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:573)
        at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$0(VertxHttpHandler.java:71)
        at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:322)
        at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190)
        at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:71)
        at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: error=2, No such file or directory
        at java.lang.UNIXProcess.forkAndExec(Native Method)
        at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
        at java.lang.ProcessImpl.start(ProcessImpl.java:134)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
        ... 36 more


The way I am calling exec function is this:



    String command1[] = new String[]{"ifconfig | grep -A 1 \'eth0\' | tail -1 |cut -d \':\' -f 2 |cut -d \' \' -f 1"};
        StringBuilder stdout = new StringBuilder();
        StringBuilder stderr = new StringBuilder();
        exec(command1, null, stdout, stderr, 30)

    String command2[] = new String[]{"./executeTest.sh ipaddress"};
     StringBuilder stdout1 = new StringBuilder();
     StringBuilder stderr1 = new StringBuilder();
     exec(command2, null, stdout1, stderr1, 30)

谁能帮我找出我在这里做错了什么?

【问题讨论】:

  • 请说明您如何称呼您的exec
  • 你可以从java.net.NetworkInterface.getNetworkInterfaces()获取(任何或全部)你自己的IP,比运行6个程序更有效

标签: java shell processbuilder


【解决方案1】:

您可能会将您的第一个命令作为一个整体提供给ProcessBuilder 的构造函数:

"ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"

ProcessBuilder 认为它是单个程序名称,因此出现错误。

尝试通过以下方式传递它:

new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"}

喜欢

exec(new String{"/bin/bash", "-c", "ifconfig| grep -A 1 'eth0'|tail -1|cut -d ':' -f 2|cut -d ' ' -f 1"},
    envt, stdout, stderr, timeoutSeconds);

ProcessBuilder 将调用bash,而bash 又将调用复杂命令。

【讨论】:

  • 对于我要触发shell脚本的第二个命令,该怎么做?如果我在第二个命令中添加“/bin/bash”、“-c”来触发我的 shell 脚本,该函数将返回代码 127。
  • 需要new String [] {"this","that","etc"}中的数组说明符
  • 对于第二个命令,通常的 `new String[] {"./executeTest.sh", "1.2.3.4"} 应该可以工作。
最近更新 更多