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

发布于 2024-11-25 14:06:56 字数 1401 浏览 2 评论 0原文

我正在尝试完成两件事:

  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") 然后执行 Runtime.getRuntime().exec("cmd /c dir ") 再次,我仍然会得到我的主文件夹的列表。有没有办法告诉进程记住其状态,就像常规 shell 一样?


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

我还添加了以下内容:

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

还是什么都没有...

但是,如果我执行这个,它就会起作用!

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

I am trying to accomplish two things:

  1. I am running cygwin on Windows7 to execute my unix shell commands and I need to automate the process by writing a Java app. I already know how to use the windows shell through Java using the 'Process class' and Runtime.getRuntime().exec("cmd /c dir"). I need to be able to do the same with unix commands: i.e.: ls -la and so forth. What should I look into?

  2. Is there a way to remember a shell's state?
    explanation: when I use: Runtime.getRuntime().exec("cmd /c dir"), I always get a listing of my home directory. If I do Runtime.getRuntime().exec("cmd /c cd <some-folder>") and then do Runtime.getRuntime().exec("cmd /c dir") again, I will still get the listing of my home folder. Is there a way to tell the process to remember its state, like a regular shell would?


It seems that the bash command line proposed by Paŭlo does not work:

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

I am having trouble figuring out the technicalities.

This is my code:

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

line ends up having a null value.


I added this to my .bash_profile:

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

I added the following as well:

System Properties -> advanced -> Environment variables -> user variebales -> variable: BASH, value: c:\cygwin\bin

Still nothing...

However, if I execute this instead, it works!

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜是你 2024-12-02 14:06:56

1.调用unix命令:

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

bash -c "ls -la"

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

ls -la

从 Java 启动此命令时,最好使用采用字符串数组的变体,如下所示
您没有 Java 让它解析以查看参数的开始和停止位置:

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

您的示例中的错误消息(ls:找不到命令)似乎表明您的 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 (换行符)分隔,例如this:

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)上的命令
命令行,您可以通过进程的输入流传递它们。

  • 以“输入模式”启动的 shell(例如,既没有 -c 选项也没有 shell 脚本文件参数的 shell)将从流中读取输入,并将第一行解释为命令(或多个命令)。的)。
  • 然后它就会执行这个命令。如果需要,命令本身可能会从流中读取更多输入。
  • 然后 shell 将读取下一行,将其解释为命令并执行。
  • (在某些情况下,shell 必须读取多行,例如长字符串或组合命令(如 if 或循环)。)
  • 这将一直持续到流的末尾(例如您这边的 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. Calling unix commands:

You simply need to call your unix shell (e.g. the bash delivered with cygwin) instead of cmd.

bash -c "ls -la"

should do. Of course, if your command is an external program, you could simply call it directly:

ls -la

When starting this from Java, it is best to use the variant which takes a string array, as then
you don't have Java let it parse to see where the arguments start and stop:

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

The error message in your example (ls: command not found) seems to show that your bash can't find the ls command. Maybe you need to put it into the PATH variable (see above for a way to do this from Java).

Maybe instead of /cygdrive/c/cygwin/bin, the right directory name would be /usr/bin.

(Everything is a bit complicated here by having to bridge between Unix and Windows
conventions everywhere.)

The simple ls command can be called like this:

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

2. Invoking multiple commands:

There are basically two ways of invoking multiple commands in one shell:

  • passing them all at once to the shell; or
  • passing them interactively to the shell.

For the first way, simply give multiple commands as argument to the -c option, separated by ; or \n (a newline), like this:

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

or from Java (adapting the example above):

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

Here the shell will parse the command line as, and execute it as a script. If it contains multiple commands, they will all be executed, if the shell does not somehow exit before for some reason (like an exit command). (I'm not sure if the Windows cmd does work in a similar way. Please test and report.)

Instead of passing the bash (or cmd or whatever shell you are using) the commands on the
command line, you can pass them via the Process' input stream.

  • A shell started in "input mode" (e.g. one which got neither the -c option nor a shell script file argument) will read input from the stream, and interpret the first line as a command (or several ones).
  • Then it will execute this command. The command itself might read more input from the stream, if it wants.
  • Then the shell will read the next line, interpret it as a command, and execute.
  • (In some cases the shell has to read more than one line, for example for long strings or composed commands like if or loops.)
  • This will go on until either the end of the stream (e.g. stream.close() at your side) or executing an explicit exit command (or some other reasons to exit).

Here would be an example for this:

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();
渔村楼浪 2024-12-02 14:06:56

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

一个例子是 JSch

You do not need cygwin here. There are several pure Java libraries implementing SSH protocol. Use them. BTW they will solve your second problem. You will open session and execute command withing the same session, so the shell state will be preserved automatically.

One example would be JSch.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文