命令行解释器如何工作?

我一直认为操作系统上的进程有三个标准流: stdin, stdout, and stderr 。 我还认为像vim这样的文本编辑通过stdin并在stdout发送ANSI转义字符来工作。 但是,我对命令行解释器如何在这一案例中没有提到的观点如下:

当我运行命令C:\cygwin\bin\bash.exe ,系统会提示我:

 Microsoft Windows [Version 6.1.7600] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Users\masson>C:\cygwin\bin\bash.exe bash-3.2$ 

…但是当我使用以下代码段在Java中运行它时,stdin流为空:

 ProcessBuilder pb = new ProcessBuilder("C:\\cygwin\\bin\\bash.exe"); pb.redirectErrorStream(true); Process proc = pb.start(); final InputStream in = proc.getInputStream(); new Thread(new Runnable() { public void run() { // Blocks forever... in.read(new byte[1024]); } }).start(); 

这里发生了什么? 我被告知bash.exe在交互模式下运行。 这是否意味着标准流未被使用? 我怎样才能继续使用这些程序,最终,我如何实现自己的cmd.exe版本? 我想我不了解命令行解释器如何工作的基本内容……

(对于讨论相关主题的文章的任何链接都将非常感激。我没有太多的运气搜索。哦,最后一个问题,在Windows中处理的标准流与在大多数类Unix操作系统中的处理方式不同?)

处于交互模式并不意味着不使用标准流。 但在这种情况下,Bash最有可能以交互模式运行(它检测到它不直接与终端应用程序通信,因此它假设它以编程方式使用,因此不打印欢迎横幅)。 在这种情况下,仍然使用标准流,只是没有输出任何内容。

正如ergosys指出的那样,在读取完整的1024字节之前,你不能真正依赖于in.read(new byte[1024])返回,尽管它可能会假设它会 – 但是,肯定不会返回在它读取至少一个字节之前,我认为这是问题 – 你甚至没有得到一个字节的输出。

尝试将“-i”传递给bash以使其以交互模式运行。

任何使用c标准库的程序都可以使用函数isatty()来判断它是否正在与tty设备(也就是命令行)进行通信。 Bash可能检测到它正在与管道而不是tty通话,并且不会输出提示。

我更像是一个Python人而不是Java人(所以我告诉你的一切都是来自JavaDoc的快速猜测),但看起来你正在设置一个多进程死锁。

in.read(new byte[1024]); 在读取1024字节数据之前不会返回,并且bash.exe在停止等待输入之前不输出整个1024字节。 (为此,请使用proc.getOutputStream()并为其提供一些命令以进行响应。)

结果,你得到Java等待bash响应和bash等待Java响应,并且完全满足于等到宇宙死亡而不会感到厌倦或疲惫。

我的建议是在每次调用in.available()之前使用in.read()来避免阻塞。 这样,您可以在输入数据和拉出数据之间来回切换而不会卡住。

实际上,将它包装在BufferedReader可能会更简单和更加简洁。

从评论更新:此外,当像bash这样的工具检测到stdin不是终端时(请参阅isatty系统调用),假设输入是非交互式的, 它们会以巨大的(4K或更多)块缓冲 。 我不确定它是否有帮助,但尝试使用-i标志启动bash。

    Interesting Posts