我有一个长时间运行的Java服务器应用程序,启动子进程执行特定任务(在这种情况下,使用命令行实用程序
7z
提取7zip文件的内容,但这个细节在这里不应该相关)。
- 服务器应用程序在Ubuntu 14下使用Java 8运行。
- 子进程通过Java ProcessBuilder API启动。
- 子进程访问的文件可能受到密码保护。
- 如果文件受密码保护且没有提供命令行参数作为密码,则
7z
程序将尝试向终端显示提示输入密码的消息,然后从终端读取密码。 - 此时,子进程会挂起,并且除非我在控制Java进程的终端上按两次
<Enter>
,否则无法完成。
7z
实用程序使用getpass系统调用来显示提示并读取用户输入。 根据文档:
由于这是服务器应用程序,因此不能接受子进程阻塞等待Java终端的输入。 相反,我希望以编程方式关闭子进程终端上的输入,以便getpass()函数打开/ dev / tty(进程的控制终端),输出字符串prompt,关闭回声,读取一行(“密码”),恢复终端状态并再次关闭/ dev / tty。
getpass
调用立即返回,并且子进程退出并出现错误代码。 不幸的是,我所有尝试关闭子进程终端的输入的尝试都导致与上述相同的行为:
- 我尝试在启动子进程后立即手动关闭
Process.getOutputStream()
返回的流。 - 我尝试使用
ProcessBuilder.redirectInput
将子进程输入重定向为从空文件和/dev/null
读取。 - 为了保险起见,我甚至尝试将
Redirect.INHERIT
传递给ProcessBuilder,即使那似乎根本不是我想要的。
这似乎是可行的,因为当7z
以与守护进程化的socat
进程相同的命令行作为子进程启动时,我观察到所需的行为,其中终端输入连接到/dev/null
,但我不知道如何使用我拥有的工具在Java中实现这一点。