【问题标题】:Why does java.lang.Process.getInputStream() return different result than a command line call?为什么 java.lang.Process.getInputStream() 返回的结果与命令行调用不同?
【发布时间】:2021-04-22 18:22:45
【问题描述】:

我尝试从存档中提取文件

我使用命令rar x file_to_extact.rar /tmp/some_dir

所以当我在命令行中执行它时,它会显示文字RAR 5.50 Copyright (c) 1993-2017 Alexander Roshal...

好的

但是当我在 java Process 中执行它时

Process process = new ProcessBuilder(new String[] { "rar", "x", "file_to_extact.rar", "/tmp/some_dir" }).start();

BufferedReader inputReader = new BufferedReader(new
    InputStreamReader(process.getInputStream()));

BufferedReader errorReader = new BufferedReader(new
    InputStreamReader(process.getErrorStream()));

String string = null;
while ((string = inputReader.readLine()) != null) {
    System.out.println(string);
}

while ((string = errorReader.readLine()) != null) {
    System.out.println(string);
}

它返回相同的单词但没有Enter password...

我知道,我可以通过命令 -p 检查存档中存在的密码,如 here 所述

但我不明白为什么命令行执行和java进程执行有一些差异

谁能解释一下:

  1. 为什么会这样?
  2. 如何正确执行命令,以获取完整信息(示例,欢迎提供链接)?

【问题讨论】:

  • 如果您询问代码,请提供您用于获取输出的代码
  • @eis 好的,我编辑了我的问题并添加了一些代码
  • 如果你按字符而不是按行阅读会怎样?
  • @BestowsInConstructoring 根据您的代码更新了我的答案

标签: java shell cmd command-line


【解决方案1】:

没有一个单一的“全力以赴”的真理。一些例子:

  1. 可执行文件可以根据附加的终端更改其行为(尤其是if it's interactive or not

  2. 输出也会根据您收听的输出流而改变。可执行文件可以打印到 stdout 或 stderr 并且这些是不同的流,您可以收听一个或另一个,两者都听或不听。而且,正如其他答案中所述,linux 密码提示可以使用直接 /dev/tty 作为密码作为安全功能,因此不使用 stdout 或 stderr。

本案可能与前者有关。可执行文件检测到您没有使用交互式 shell 并相应地修改其行为。

但是,对于这种情况,也可能是您没有从 processbuilder 正确获取输出。

您似乎在这里获取完整的行:

while ((string = inputReader.readLine()) != null) {
    System.out.println(string);
}

但是密码提示不是一个完整的行。获取所有字符可能会使其可见:

int r;
while ((r = reader.read()) != -1) {
    char ch = (char) r;
    System.out.print(ch);
}

注意:上面的示例仅适用于 ascii 字符,如果您需要支持更大的字符集,则需要更多编码。这只是为了演示逐字阅读。

【讨论】:

  • 1) 据我了解,如果我想获得与 shell 结果相同的结果,我需要在交互模式下运行命令。是还是不是? 2)无论如何,你能否请一个我需要在java中使用的命令示例以获得相同的结果? 3)我尝试读取字符,结果是一样的
  • @BestowsInConstructoring 1) 也许。一些可执行文件以这种方式工作,不知道 rar 可执行文件在内部做什么。 2 & 3) 那么你就不走运了,想不出用 java 能得到同样结果的方法。
【解决方案2】:

Enter password 不显示在标准输出中,也不从标准输入中读取。这是 Unix/Linux 程序中长期存在的做法,以保证密码安全:直接从控制台/tty 读取密码(这也是程序防止输入的密码被回显的方式)。

虽然您可以将密码作为参数发送到 -p 命令行选项,但请注意,这是非常不安全的,因为它会将密码暴露给检查进程列表的任何其他用户。

new ProcessBuilder("rar", "x", "-p" + password, "file_to_extact.rar", "/tmp/some_dir")

同样,这是非常不安全的。在命令运行时,任何用户都可以检查进程,并会显示如下内容:

  PID TTY      STAT   TIME COMMAND
 8732 pts/3    S+     0:00 rar x -pswordfish123 file_to_extact.rar /tmp/some_dir

您需要考虑将密码暴露给系统上的临时观察者的风险。

我不知道有什么方法可以自动执行直接从控制台读取的外部命令。

但是,this question 地址使用 Java 而不是外部命令来读取 rar 存档。 junrar 似乎是一个受欢迎的选择。 (我没用过,效果不好说。)

【讨论】:

  • 我认为,基于这个问题,OP 已经知道 -p 开关,但仍然想知道为什么他没有在他的用例中看到密码提示(您回复的第一段给出了回答)
  • @eis 谢谢,你是对的。更新了我的回答中的语言以承认这一点。
  • 感谢您提供重要的安全信息! ! !
【解决方案3】:

这是因为rar 可执行文件显式地找到了一个/终端并在那里询问,或者如果它不能,则确定会话不是交互式的并且拒绝提示输入这样的密码。它不会故意将“输入密码”提示发送到标准输出(或标准错误)。它这样做的原因是专门停止你正在做的事情。这可能过于热心了,但您必须与 Alexander Roshal 和朋友一起接受。

解决办法是完全重写。使用:例如junrar。您最终会得到更加健壮和灵活的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多