4

我一直认为操作系统上的进程具有三个标准流:stdin, stdout, and stderr. 我还认为像 vim 这样的文本编辑器通过接管输入stdin和发送 ANSI 转义字符来工作stdout。但是,在这种情况下,我对命令行解释器的看法并没有得到支持:

当我运行命令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 中运行它时,标准输入流是空的:

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 操作系统中的处理方式有什么不同吗?)

4

3 回答 3

4

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

于 2010-09-05T05:37:00.783 回答
1

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

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

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

于 2010-09-06T07:00:08.110 回答
1

我更像一个 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。

于 2010-09-05T05:29:06.660 回答