Entendendo a interação terminal e shell

3

Por um longo tempo, meu entendimento sobre um terminal em sistemas unix-like foi que ele inicia o processo do shell e fornece uma interface com o usuário, comunicando-se com ele sobre o stdin , stdout & stderr .

No entanto, recentemente, ao olhar para um problema com o lançamento de um aplicativo de console do Windows através de um terminal cygwin, percebo que pode não ser tão simples quanto isso.

No link ,

Another issue is receiving output from or giving input to console-based Windows programs. Unfortunately, interacting with Windows console applications is not a simple matter of using a translation utility. Windows console applications are designed to run under command.com or cmd.exe, and some do not deal gracefully with other situations. Cygwin can receive console input only if it is also running in a console (DOS box) since Windows does not provide any way to attach to the backend of the console device. Another traditional Unix input/output method, ptys (pseudo-terminals), is supported by Cygwin but not entirely by Windows. The basic problem is that a Cygwin pty is a pipe and some Windows applications do not like having their input or output redirected to pipes.

Eu escrevi um pequeno programa em C que eu compilei no windows usando o cl.exe -

do 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;
}

Quando eu executo o terminal Cygwin ( mintty.exe ) e inicio este programa, não consigo interagir com ele -

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

^ - sem resposta

Mas quando eu coloco em um tubo, funciona -

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

Basicamente, ele não consegue interagir com o terminal mintty.exe . No entanto, quando executando bash.exe diretamente de um console do Windows, ele pode ser corretamente interagido com -

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

Eu então pensei que se eu ssh estivesse na minha máquina e executasse este programa como um comando, ele funcionaria como se o terminal não interagisse diretamente com ele, mas o servidor SSH funcionaria. No entanto, isso não funciona também -

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

^ - sem resposta

Mas colocar isso em um cano novamente funciona! -

[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 ~]$

Alguém poderia explicar a teoria por trás de todas essas observações?

A interação entre o terminal e o shell é mais do que apenas o uso do stdin do shell, stdout e stderr ?

Como o console do Windows é diferente? Por que os programas do console do Windows parecem funcionar bem quando estão em um canal com os programas cygwin?

    
por 0cd 03.05.2013 / 12:14

1 resposta

2

Se você adicionar fflush(stdout) ao seu loop while (depois de printf ), seu programa funcionará como esperado, mesmo dentro do Mintty. Você também deve poder chamar setbuf(stdout, NULL) como a primeira operação que você faz no stdout e ter esse trabalho.

Você também pode executar c: \ cygwin \ bin \ bash dentro da janela do console do Windows e seu programa original funcionará como você, exceto. Eu não tentei, mas você também deve ser capaz de executar o bash dentro de uma janela do console ou do console2 e fazer o seu programa original funcionar conforme o esperado.

Isso é para dizer: isso é sobre menta.

Aqui está (parte do) o que está acontecendo:

O console do Windows é muito especial. O Windows possui um serviço chamado Subsistema de Tempo de Execução Cliente / Servidor. Quando você inicia um prompt do cmd no Windows, o que você está realmente fazendo é conectar-se ao Subsistema de Tempo de Execução do Cliente / Servidor, e ele está criando a janela para você.

O Mintty, por outro lado, é uma janela "regular" (que por acaso está rodando um emulador de terminal).

As rotinas de e / s da biblioteca C da Microsoft realmente testam se estão sendo executadas em uma janela criada pelo Subsistema Runtime do Cliente / Servidor e mudam seu comportamento se estiverem. Uma mudança que eles fazem é desativar o buffer completo para stdout.

Quando você executa sob o comando mintty, as rotinas gets / puts do Windows acham que elas não estão sendo executadas em um prompt de comando, portanto, elas estão fazendo um buffer completo.

Eis mais um truque: em bash em execução em mintty , é possível executar cat | echo1.exe . Em seguida, digite algumas coisas e quando você atingir ^D , toda a saída stdout armazenada em buffer será mostrada de uma só vez.

O motivo pelo qual o truque cat | echo1.exe funciona é que cat é um programa cygwin. O Cygwin é, no fundo, uma biblioteca de emulação posix. Portanto, o stdin de cat é emulado pela biblioteca do Cygwin e a biblioteca do Cygwin trata ^D de maneira diferente de um stdin do Windows "real".

Mas se você executar apenas echo1.exe em bash sob mintty , suas teclas estarão entrando em um fluxo de arquivo não emulado (ou seja, seu stdin é um stdin real do Windows, não é emulado pela biblioteca Cygwin) , então ^D não envia eof. Em vez disso, ^Z enviaria eof, mas ^Z significa algo especial para bash, por isso não é enviado. Em vez disso, você precisa acessar ^C , que finaliza echo1.exe imediatamente (e não libera os buffers, o que está correto).

    
por 03.05.2013 / 15:02