如何使用Java进程获取shell脚本的提示信息

xa9qqrwz  于 2023-06-06  发布在  Shell
关注(0)|答案(2)|浏览(309)

我使用java.lang.Process来执行shell脚本,它需要用户交互输入。在Java中,我无法获得请求用户输入的提示消息。
在这个例子中,我想得到**“输入你的名字:“**在Java进程中执行。

read -p 'Enter your name: ' name;
echo "Hello, $name!"

我尝试通过Process InputStream和ErrorStream获取shell脚本输出。他们只能得到回声输出。
此代码仅打印

outputFuture:你好,myName!

ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "read -p 'Enter your name: ' name; echo \"Hello, $name!\"");
Process process = pb.start();
InputStream is = process.getInputStream();
InputStream es = process.getErrorStream();

// Create a separate thread to read the output of the process
ExecutorService executor = Executors.newSingleThreadExecutor();

Future<String> outputFuture = executor.submit(() -> {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    String line;
    while ((line = reader.readLine()) != null) {
        return line;
    }
    return null;
});

//Input myName to continue shell script  
OutputStream os = process.getOutputStream();
os.write("myName\n".getBytes());
os.flush();
Thread.sleep(1000);

//Reading ErrorStream
BufferedReader reader = new BufferedReader(new InputStreamReader(es));
String line;
while ((line = reader.readLine()) != null) {
    LOGGER.info("error reader: {}", line);
}
int exitCode = process.waitFor();
LOGGER.info("Script exited with code " + exitCode);

// Display the output of the process
String output = outputFuture.get();
if (output != null) {
    LOGGER.info("outputFuture: {}", output);
}

executor.shutdown();
42fyovps

42fyovps1#

read-p参数仅在stdin附加到终端时才有效。引用shell的源代码:

/* If the -p, -e or -s flags were given, but input is not coming from the
     terminal, turn them off. */
  if ((prompt || edit || silent) && input_is_tty == 0)
    {
      prompt = (char *)NULL;
#if defined (READLINE)
      itext = (char *)NULL;
#endif
      edit = silent = 0;
    }

你可以将bash的副本 Package 在类似unbuffer的东西中,以模拟TTY(ProcessBuilder("/usr/bin/unbuffer", "/bin/bash", "-c", ...),但我通常建议首先不要依赖-p(这是有原因的,被编程调用的工具通常通过环境变量或命令行接受参数)。

qlfbtfca

qlfbtfca2#

看起来bash内置调用read并没有写入stdout或stderr,也许它写入了自己的控制台。Java也看不到。您可以在bash shell中运行以下命令进行确认:

prompt> read -p 'Enter your name: ' name; echo "Hello, $name!" 2>&1 | tee /tmp/stdout.log
Enter your name: blah
Hello, blah!
prompt> cat /tmp/stdout.log
Hello, blah!

如果您想看到输出的消息,您可以更改命令以使用echoecho -n,这样提示符会首先出现。

ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "echo  'Enter your name: ' ; read name ; echo \"Hello, $name!\"");

您可以使用以下命令捕获所有stdout行:

Future<List<String>> outputFuture = executor.submit(() -> {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    return reader.lines().toList();
});

请注意,如果您期望stdin更大,则需要更多线程(stdout和stderr消费者各一个),或者保留一个后台线程并使其读取组合的stdout+stderr - add pb.redirectErrorStream(true)

相关问题