为什么 java.lang.Process.getInputStream() return 与命令行调用的结果不同?

Why does java.lang.Process.getInputStream() return different result than a command line call?

我尝试从存档中提取文件

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

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

好的

但是当我在java进程中执行它时

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);
}

它return相同的词但没有Enter password...

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

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

谁能解释一下:

  1. 为什么会这样?
  2. 如何正确的执行命令,得到完整的(例子,欢迎链接)?

没有“满”这个道理。一些例子:

  1. 可执行文件可以根据连接的终端更改其行为(特别是,if it's interactive or not

  2. 输出也会根据您收听的输出流而改变。可执行文件可以打印到 stdout 或 stderr,它们是不同的流,您可以听一个或另一个,两者或 none。并且,如其他答案所述,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 字符,如果您需要支持更大的字符集,则需要更多编码。这只是为了演示逐字阅读。

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

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

Enter password 没有显示在标准输出中,也没有从标准输入中读取。这是 Unix/Linux 程序中长期存在的做法,以确保密码安全:直接从 console/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 addresses using Java, rather than an external command, to read a rar archive. junrar 似乎是一个受欢迎的选择。 (我没用过,所以不好说。)