命令行解释器如何工作?

时间:2010-09-05 04:42:28

标签: java shell command-line stream ansi

我一直认为操作系统上的进程有三个标准流: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操作系统中的处理方式不同? )

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

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

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

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

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

事实上,将它包装在BufferedReader中可能要简单得多,而且更加精明。

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

答案 2 :(得分:1)

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

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

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