如何使用Java通过Windows / cygwin执行unix命令

时间:2011-07-19 18:09:39

标签: java unix shell windows-7 cygwin

我正在努力完成两件事:

  1. 我在Windows7上运行cygwin来执行我的unix shell命令,我需要通过编写Java应用程序来自动化该过程。我已经知道如何使用'Process class'和Runtime.getRuntime().exec("cmd /c dir")通过Java使用windows shell。我需要能够使用unix命令执行相同的操作:即:ls -la等等。我该怎么看?

  2. 有没有办法记住shell的状态? 解释:当我使用:Runtime.getRuntime().exec("cmd /c dir")时,我总是得到我的主目录列表。如果我执行Runtime.getRuntime().exec("cmd /c cd <some-folder>")然后再次执行Runtime.getRuntime().exec("cmd /c dir"),我仍会获得我的主文件夹列表。有没有办法告诉进程记住它的状态,就像常规shell一样?


  3. 似乎Paŭlo提出的bash命令行不起作用:

    C:\cygwin\bin>bash -c ls -la
    -la: ls: command not found
    

    我无法弄清楚技术性。

    这是我的代码:

    p = Runtime.getRuntime().exec("C:\\cygwin\\bin\\bash.exe -c ls -la");
    reader2 = new BufferedReader(new InputStreamReader(p.getInputStream()));
    line = reader2.readLine();
    

    line最终会出现空值。


    我将此添加到我的.bash_profile:

    #BASH
    export BASH_HOME=/cygdrive/c/cygwin
    export PATH=$BASH_HOME/bin:$PATH
    

    我还添加了以下内容:

      

    系统属性 - &gt;高级 - &gt;环境变量 - &gt;用户variebales - &gt;变量:BASH,值:c:\cygwin\bin

    仍然没有...

    但是,如果我执行此操作,它会起作用!

    p = Runtime.getRuntime().exec("c:\\cygwin\\bin\\ls -la ~/\"Eclipse_Workspace/RenameScript/files copy\"");
    

2 个答案:

答案 0 :(得分:10)

<强> 1。调用unix命令:

你只需要调用你的unix shell(例如用cygwin提供的bash)而不是cmd

bash -c "ls -la"

应该这样做。当然,如果你的命令是外部程序,你可以直接调用它:

ls -la

从Java开始时,最好使用带有字符串数组的variant,然后使用 你没有Java让它解析以查看参数的开始和停止位置:

Process p = 
     Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
                                            "-c", "ls -la"},
                               new String[]{"PATH=/cygdrive/c/cygwin/bin"});

示例中的错误消息(ls: command not found)似乎表明您的bash找不到ls命令。也许你需要把它放到PATH变量中(参见上面的方法来从Java中做到这一点)。

可能代替/cygdrive/c/cygwin/bin,正确的目录名称为/usr/bin

(由于必须在Unix和Windows之间架起桥梁,所以这里有点复杂  各地的惯例。)

可以像这样调用简单的ls命令:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\ls.exe", "-la"});

<强> 2。调用多个命令:

在一个shell中基本上有两种调用多个命令的方法:

  • 将它们全部传递给shell;或
  • 以交互方式将它们传递给shell。

对于第一种方式,只需将多个命令作为-c选项的参数,由;\n(换行符)分隔,如下所示:

bash -c "cd /bin/ ; ls -la"

或来自Java(适应上面的例子):

Process p = 
     Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe",
                                            "-c", "cd /bin/; ls -la"},
                               new String[]{"PATH=/cygdrive/c/cygwin/bin"});

这里shell会将命令行解析为,并将其作为脚本执行。如果它包含多个命令,如果shell由于某种原因(例如exit命令)之前没有以某种方式退出,则它们都将被执行。 (我不确定Windows cmd是否以类似的方式工作。请测试并报告。)

而不是传递bash(或cmd或你正在使用的任何shell)上的命令 命令行,您可以通过Process的输入流传递它们。

  • 以“输入模式”启动的shell(例如,既没有-c选项也没有shell脚本文件参数的shell)将从流中读取输入,并将第一行解释为命令(或几个)。
  • 然后它将执行此命令。如果需要,命令本身可能会从流中读取更多输入。
  • 然后shell将读取下一行,将其解释为命令,然后执行。
  • (在某些情况下,shell必须读取多行,例如对于长字符串或组合命令,如if或loops。)
  • 这将一直持续到流的末尾(例如你身边的stream.close())或执行显式exit命令(或退出的其他一些原因)。

这是一个例子:

Process p = Runtime.getRuntime().exec(new String[]{"C:\\cygwin\\bin\\bash.exe", "-s"});
InputStream outStream = p.getInputStream(); // normal output of the shell
InputStream errStream = p.getInputStream(); // error output of the shell
// TODO: start separate threads to read these streams

PrintStream ps = new PrintStream(p.getOutputStream());
ps.println("cd /bin/");
ps.println("ls -la");
ps.println("exit");
ps.close();

答案 1 :(得分:1)

你这里不需要cygwin。有几个实现SSH协议的纯Java库。使用它们。 BTW他们将解决你的第二个问题。您将使用相同的会话打开会话和执行命令,因此将自动保留shell状态。

一个例子是JSch