【问题标题】:Execute a command in Linux using Java and fetch the output使用 Java 在 Linux 中执行命令并获取输出
【发布时间】:2011-11-08 11:44:21
【问题描述】:

我正在使用 Groovy 在我的 Linux 机器上执行命令并取回输出,但我无法以某种方式使用 | 管道(我认为)或者它可能没有等待命令完成。

我的代码有什么问题或遗漏了什么?

我的调用函数:

def test()
{
    String result="N"

    HashMap<String,String> params = IntermediateResults.get("userparams")
    Map env=AppContext.get(AppCtxProperties.environmentVariables)

    def fClass = new GroovyClassLoader().parseClass( new File( 'plugins/infa9/Infa9CommandExecUtil.groovy' ) )
    List<String> frows=["uname -a",
                        "uname -a | awk '{print\$2}'",
                        "uname -a | cut -d ' ' -f 2"]
    List<String> resultRows = fClass.newInstance().fetchCommandOutput( params, env, frows )

    return result
}

Infa9CommandExecUtil.groovy文件内容(更新:添加exitVal println):

package infa9

import java.io.BufferedReader;

public class Infa9CommandExecUtil {
  StringBuffer result

  public Infa9CommandExecUtil() {
    result = new StringBuffer()
  }

  public List<String> fetchCommandOutput( Map<String,String> params, Map env, List<String> rows )
  {

        List<String> outputRows = new ArrayList<String>()
        try
        {
            for(item in rows)
            {
                String temp=item.toString()
                println "CMD:$temp"
                Process proc = Runtime.getRuntime().exec(temp);
                InputStream stdin = proc.getInputStream();
                InputStreamReader isr = new InputStreamReader(stdin);
                BufferedReader br = new BufferedReader(isr);
                String line = null;

                result = new StringBuffer()
                line=null

                int exitVal = proc.waitFor()    //do I need to wait for the thread/process to finish here?

                while ((line = br.readLine()) != null)
                {
                    result.append(line+System.getProperty("line.separator"))    //to maintain the format (newlines)
                }
                String tRes=result
                tRes=tRes.trim()
                println "OUTPUT:$tRes\nEXITVAL:$exitVal"

                outputRows.add(tRes)
            }
        }
        catch (IOException io)  {   io.printStackTrace();}
        catch (InterruptedException ie) {ie.printStackTrace();}
    return  outputRows
  }
}

我的输出(更新:添加了 exitVal 值):

CMD:uname -a
OUTPUT:Linux estilo 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
EXITVAL:0
CMD:uname -a | awk '{print$2}'
OUTPUT:
EXITVAL:1
CMD:uname -a | cut -d ' ' -f 2
OUTPUT:
EXITVAL:1

注意:我在内部使用sh -c &lt;command&gt;

【问题讨论】:

  • 那么,您仍然没有以 Groovy 的方式进行操作(我已经向您展示了好几次)?
  • @tim:我落后了,我以为我会先满足要求,然后重构代码。对不起:)
  • 我也会读取错误流或使用 ProcessBuilder 将错误定向到输出。我会将输出复制到 ByteArrayOutputStream 并将其转换为字符串。
  • @Peter Lawrey:你能举个例子吗,这将是一个很大的帮助。谢谢
  • 我认为您不应该从 Java 调用非 Java 程序。否则,何必一开始就用 Java 编写代码呢?

标签: java groovy


【解决方案1】:

您不能使用String.execute() 进行管道或重定向。这在 Java 中不起作用,所以在 Groovy 中也不起作用……

您可以将Process.pipeTo 与 Groovy 一起使用来简化事情:

Process proca = 'uname -a'.execute()
Process procb = 'awk {print\$2}'.execute()

(proca | procb).text

更通用的版本可能是:

String process = 'uname -a | awk {print\$2}'

// Split the string into sections based on |
// And pipe the results together
Process result = process.tokenize( '|' ).inject( null ) { p, c ->
  if( p )
    p | c.execute()
  else
    c.execute()
}
// Print out the output and error streams
result.waitForProcessOutput( System.out, System.out )

【讨论】:

  • 谢谢,.inject(null)p,c-&gt; 在这里做什么?
  • @Ab inject method 以一个初始累加器值(在本例中为 null)开始,然后沿着 Collection 依次对每个元素应用闭包(Closure 得到的结果放入下一个元素的累加器中)。所以在这种情况下,我们从 null 开始,然后第一次迭代将其设置为 c.execute()(其中 c 是我们在列表中的第一个元素),然后第二个循环 p 是由此产生的 Process,并且所以它将累加器设置为p | c.execute()。希望这有意义吗?
  • @AbhishekSimon 我不明白这个问题...result.waitForProcessOutput( System.out, System.out ) 将输出和错误流从流程链重定向到System.out。所以一切都显示在同一个流上......
  • 感谢它的魅力。我会在我的问题中发布完整的功能,作为其他人的更新:)
【解决方案2】:

管道| 是像bash 这样的shell 的一个特性。要使用管道,您需要运行一个 shell,例如

"/bin/bash", "-c", "uname -a | awk '{print $2}'"

要使用带有重定向的 ProcessBuilder,您可以这样做

public static void main(String... args) throws IOException, InterruptedException {
    final String cmd = "uname -a | awk '{print $1 \" \" $3}'";
    System.out.println(cmd + " => " + run(cmd));
}

private static String run(String cmd) throws IOException, InterruptedException {
    final ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", cmd);
    pb.redirectErrorStream();
    final Process process = pb.start();
    final InputStream in = process.getInputStream();
    final byte[] bytes = new byte[1024];
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // you must read the output as the program runs or it can stall.
    for (int len; (len = in.read(bytes)) > 0;)
        baos.write(bytes, 0, len);
    process.waitFor();
    return baos.toString(); // assuming the default char encoding is ok.
}

打印

uname -a | awk '{print $1 " " $3}' => Linux 2.6.18-274.3.1.el5

【讨论】:

    【解决方案3】:

    管道是外壳的一个特征。所以如果你想支持管道,你必须在 shell 上下文中运行你的命令,即你在 java 中传递给exec 的命令行应该看起来像/bin/sh YOUR_COMMAND

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      • 2014-06-29
      • 2013-01-01
      • 2010-10-03
      相关资源
      最近更新 更多