【发布时间】:2012-02-05 17:47:17
【问题描述】:
我正在寻找一种最有效的决定方式:
- 我是否应该在用户提供的命令行中添加 shell 可执行文件
- 如果是,该可执行文件是什么? (/bin/sh?/usr/bin/perl?/usr/bin/ksh?c:/../cmd.exe?)
众所周知,要从 Java 启动 shell 脚本,应该启动 shell:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "script.sh", "arg1", "arg2);
要启动二进制文件,应该启动二进制文件本身:
ProcessBuilder pb = new ProcessBuilder("/path/binary", "arg1", "arg2);
如果使用 shell 执行二进制文件,则会产生错误:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "/path/binary", "arg1", "arg2);
(sh: cannot execute binary file)
如果在没有 shell 二进制文件的情况下执行 shell 脚本,则会产生错误:
ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)
我的应用程序不知道它从什么开始,二进制或脚本。
启动的应用程序是最终用户提供的事件处理程序。它很可能是在 Unix 下执行的 shell 脚本;但它可以是 Windows 下的 *.cmd,也可以是在某个不起眼的平台下执行的 Perl 脚本。毕竟是 Java。
我第一次天真的尝试是用 shell 启动命令行,看看它是否有效。如果没有,请尝试将其作为二进制文件执行。
这是丑陋和危险的:在某些未知的平台和外壳组合下,第二次运行可能仍然执行脚本,第二次,结果不可预测。
另外,从我无法启动脚本开始,我无法判断脚本何时启动正常并由于自身的某些问题而失败。
我现在考虑的最好的事情是:
- 阅读脚本并查找任何不可打印的字节
- 如果找到,将其视为二进制文件
- 如果没有,添加 /bin/sh(或 cmd.exe,如果在 Windows 下)
如果您有更好的想法,请告知。
更新/部分解决方案
感谢所有与我分享想法的人。
事实证明,我把自己和互联网上的其他人都搞糊涂了 :)
不需要在用户输入的命令行之前添加 shall 二进制文件,前提是:
- 脚本在 PATH 中
- (对于 Unix)脚本是可执行的
- (对于 Unix)脚本有 #!/path/to/interpreter
当我测试我的代码时,其中一个或另一个条件没有满足。 :-(
从头开始仔细执行测试后,脚本已经执行。
第 3 点只能由用户完成,并且必须记录在用户手册中。
由于这些脚本传播到目标系统的方式,它们可能无法执行并且可能不在 PATH 中。
我关心的唯一路径是相对路径,所以在任何相对路径前面加上 ./ 就足够了。
使脚本在 Unix(和任何其他平台)下可执行是一个更大的挑战。这不是WORA。将 /bin/sh 放在它前面可能会有所帮助,但如果我记得在 Solaris 下,shell 将不会执行不可执行的脚本。
我将在本周晚些时候发布另一个更新。
【问题讨论】:
-
您的 shell 脚本顶部是否有适当的 shebang 行 (
#!)?如果是这样,那么您可以简单地要求内核运行它(只要它是+x可执行文件),而不必担心它可能需要哪个命令解释器。 -
我不知道。该脚本来自最终用户,不随软件提供。
标签: java shell exec processbuilder