繁体   English   中英

Java,Runtime.exec或ProcessBuilder:如何知道文件是shell还是二进制文件?

[英]Java, Runtime.exec or ProcessBuilder: how to know if the file is shell or binary?

我正在寻找一种最有效的方法来决定:

  • 我应该使用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启动命令行,看它是否有效。 如果没有,请尝试将其作为二进制文件执行。

这是丑陋和冒险的:在平台和shell的一些未知组合下,第二次运行仍然可能仍然执行脚本,第二次,具有不可预测的结果。

此外,我无法判断脚本何时启动正常并且由于某些问题而失败,因为我无法启动它。

我现在考虑的最好的事情是:

  • 阅读脚本并查找任何不可打印的字节
  • 如果找到,请将其视为二进制
  • 如果没有,请添加/ bin / sh(如果在Windows下,则添加cmd.exe)

如果您有任何更好的想法,请告知。

更新/部分解决方案

感谢所有与我分享他们想法的人。

事实证明,我把自己和互联网的其他部分弄糊涂了:)

在用户输入的命令行之前不需要在应用二进制文件前加前缀,前提是:

  1. 该脚本位于PATH中
  2. (对于Unix)脚本是可执行的
  3. (对于Unix)脚本有#!/ path / to / interpreter

当我测试我的代码时,这些条件中的一个或另一个没有达到。 :-(

从临时脚本执行测试后,脚本已经执行完毕。

第3点只能由用户完成,并且必须在用户手册中记录。

由于这些脚本传播到目标系统的方式,它们可能不可执行,可能不在PATH中。

我关心的唯一路径是相对路径,因此将./添加到任何相对路径就足够了。

使脚本在Unix(以及任何其他平台)下可执行是一个更大的挑战。 这不是WORA。 在它前面放置/ bin / sh可能会有所帮助,但如果我记得在Solaris下,shell将不会执行非可执行脚本。

我将在本周晚些时候发布另一个更新。

它应该是一个红旗,你必须跳过这些箍只是为了运行一个命令。 首先是因为这变得非常复杂,其次是因为Java被设计为独立于平台。 当您研究特定于操作系统的黑客攻击以使内置类工作时,您应该退后一步并重新检查您的假设。

ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2);
(error 2: file not found)

请注意,错误消息是“找不到文件”,而不是“无法执行shell脚本”或某些此类错误。 导致此错误的最可能原因不是您正在执行脚本,而是找不到该脚本。

如果脚本在当前目录中,则需要在前面添加./ 如果未将可执行文件放在显式路径中,则可执行文件必须位于$PATH环境变量的其中一个目录中。 当前目录. 默认情况下通常包含在$PATH

ProcessBuilder pb = new ProcessBuilder("./script.sh", "arg1", "arg2);

如果脚本名称是用户提供的值,那么我会对用户征收此要求 - 您可以为它们添加./ ,但UNIX程序通常会尽量避免过于有用。 如果他们忘了把./那就是他们的问题!

一种可能的解决方案是生成一个脚本,该脚本包含程序中的执行脚本/二进制文件。 这样你知道它总是一个脚本。 生成的脚本只执行内部脚本/二进制文件并返回错误代码(并可能重定向输入/输出)。 完成后,您只需删除它即可。 Java允许您非常轻松地创建临时文件。

ProcessBuilder pb = new ProcessBuilder(“/ bin / sh”,“/ path / binary”,“arg1”,“arg2);(sh:无法执行二进制文件)

ProcessBuilder pb = new ProcessBuilder(“/ bin / sh”,“ - c”,“/ path / binary”,“arg1”,“arg2);(sh:无法执行二进制文件)

一种选择是接受来自用户的解释器路径作为另一个参数(可能来自已知值的列表)。

(这可能是一个评论。我无法正确格式化)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM