我正在寻找一种最有效的方式来决定:
- 我应该在用户提供的命令行中添加 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 将不会执行不可执行的脚本。
我将在本周晚些时候发布另一个更新。