命令行解释器如何工作?

问题描述 投票:0回答:3

我的印象是操作系统上的进程具有三个标准流:

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

java shell command-line stream ansi-escape
3个回答
4
投票

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


1
投票

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

正如 ergosys 指出的那样,您不能真正依赖

in.read(new byte[1024])
在它读取完整的 1024 个字节之前返回,尽管可以假设它会返回 - 但是,它肯定不会在读取至少一个之前返回字节,我认为这就是这里的问题 - 你甚至没有得到一个字节的输出。

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


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 系统调用),他们假设输入是非 -交互的。我不确定它是否有帮助,但请尝试使用 -i 标志启动 bash。

© www.soinside.com 2019 - 2024. All rights reserved.