了解终端和 shell 交互

了解终端和 shell 交互

很长一段时间以来,我对终端在类 Unix 系统中,它启动 shell 进程并通过其与它通信来为其提供用户界面标准输入标准输出&标准错误

然而最近在研究通过 cygwin 终端启动 Windows 控制台应用程序的问题时,我意识到它可能不是那么简单。

http://cygwin.com/1.5/cygwin-ug-net/using-effectively.html我懂了,

另一个问题是从基于控制台的 Windows 程序接收输出或向其提供输入。遗憾的是,与 Windows 控制台应用程序交互并不是使用转换实用程序的简单问题。Windows 控制台应用程序设计为在 command.com 或 cmd.exe 下运行,有些应用程序不能很好地处理其他情况。Cygwin 只有在控制台(DOS 框)中运行时才能接收控制台输入,因为 Windows 不提供任何连接到控制台设备后端的方法。另一种传统的 Unix 输入/输出方法 ptys(伪终端)受 Cygwin 支持,但 Windows 并不完全支持。基本问题是 Cygwin pty 是一个管道,有些 Windows 应用程序不喜欢将其输入或输出重定向到管道。

我写了一个小 C 程序,并在 Windows 下使用 VC++ 进行了编译进程管理器-

#include <stdio.h>

int main(int argc, char *argv[]) {
    #define BUFFER_LEN 1024
    char buffer[BUFFER_LEN];

    printf("echo server started\n"); 
    while (fgets(buffer, BUFFER_LEN, stdin) != NULL) {
        printf("%s", buffer);
    }

    return 0;
}

当我运行 Cygwin 终端时(执行程序)并启动该程序,我无法与其交互 -

[puneet@freestyle ~]$ /cygdrive/c/echo1.exe
Hello

^-- 没有回应

但当我把它放进管道里时,它就起作用了——

[puneet@freestyle ~]$ echo  -e "1\n2\n3" | /cygdrive/c/echo1.exe | while read line; do echo $line; done
1
2
3
[puneet@freestyle ~]$

基本上它无法与执行程序终端。然而当运行执行程序直接从 Windows 控制台,它可以正确地与 - 进行交互

[puneet@freestyle ~]$ /cygdrive/c/echo1.exe
Hello
Hello
^Z
[puneet@freestyle ~]$

然后我想如果我远程控制'd 进入我的机器并运行这个程序作为命令,它会工作,因为终端不会直接与它交互,但 SSH 服务器会。然而这也行不通 -

[puneet@freestyle ~]$ ssh freestyle /cygdrive/c/echo1.exe
Hello

^-- 没有回应

但是把它放进管道里又可以了!-

[puneet@freestyle ~]$ echo  -e "1\n2\n3" | ssh freestyle /cygdrive/c/echo1.exe | while read line; do echo $line; done
1
2
3
[puneet@freestyle ~]$

有人能解释一下这些观察背后的理论吗?

终端和 shell 之间的交互是否不仅仅是使用 shell 的标准输入标准输出标准错误

Windows 控制台有何不同?为什么 Windows 控制台程序在与 cygwin 程序的管道中似乎运行良好?

答案1

如果您在循环fflush(stdout)中添加while(在之后printf),那么您的程序将按预期运行,即使在 mintty 中也是如此。您还应该能够将调用setbuf(stdout, NULL)作为您在 stdout 上执行的第一个操作,并使其运行。

您还可以在 Windows 控制台窗口内运行 c:\cygwin\bin\bash,您的原始程序将按预期运行。我还没有尝试过,但您也应该能够在 conemu 或 console2 窗口内运行 bash,并让您的原始程序按预期运行。

也就是说:这是关于薄荷的。

以下是正在发生的事情(部分):

Windows 控制台非常特殊。Windows 有一个名为客户端/服务器运行时子系统的服务。当您在 Windows 上启动 cmd 提示符时,您实际上是在连接到客户端/服务器运行时子系统,并且正在为您创建窗口。

另一方面,Mintty 是一个“常规”窗口(恰好运行终端模拟器)。

Microsoft 的 C 库 i/o 例程实际上会测试它们是否在客户端/服务器运行时子系统创建的窗口下运行,如果是,则更改其行为。它们所做的一项更改是关闭 stdout 的完全缓冲。

当您在 mintty 下运行时,Windows 的 gets/puts 例程认为它们没有在命令提示符中运行,因此它们正在进行完全缓冲。

这里还有一个技巧:在bash运行 under时,mintty您可以运行cat | echo1.exe。然后输入一些内容,当您点击时,^D所有缓冲的 stdout 输出将同时显示出来。

这个cat | echo1.exe技巧之所以有效,是因为这cat是一个 cygwin 程序。Cygwin 本质上是一个 posix 模拟库。因此stdinofcat是由 Cygwin 库模拟的,而 Cygwin 库的处理方式^D与“真正的”Windows stdin 不同。

但是如果你只是在under underecho1.exe下运行,那么你的按键将进入非模拟文件流(即,你的 stdin 是真正的 Windows stdin,而不是 Cygwin 库模拟的 stdin),因此不会发送 eof。相反,它会发送 eof,但对 bash 来说意味着一些特殊的东西,所以它不会被发送。相反,你需要立即终止(并且不会刷新缓冲区,这是正确的。)bashmintty^D^Z^Z^Cecho1.exe

相关内容