Grundlegendes zur Interaktion zwischen Terminal und Shell

3

Für eine lange Zeit bestand mein Verständnis über ein Terminal in Unix-ähnlichen Systemen darin, dass es den Shell-Prozess startet und eine Benutzeroberfläche bereitstellt, indem es mit ihm über stdin , stdout & stderr kommuniziert .

Als ich mich kürzlich mit einem Problem beim Starten einer Windows-Konsolenanwendung über ein Cygwin-Terminal befasste, wurde mir klar, dass es möglicherweise nicht so einfach ist.

Unter http://cygwin.com/1.5/cygwin-ug-net/using-effective.html sehe ich,

Ein weiteres Problem besteht darin, Ausgaben von konsolenbasierten Windows-Programmen zu empfangen oder Eingaben an diese zu senden. Die Interaktion mit Windows-Konsolenanwendungen ist leider nicht einfach, wenn Sie ein Übersetzungsdienstprogramm verwenden. Windows-Konsolenanwendungen können unter command.com oder cmd.exe ausgeführt werden, und einige reagieren nicht ordnungsgemäß auf andere Situationen. Cygwin kann nur Konsolen-Eingaben empfangen, wenn es auch in einer Konsole (DOS-Box) ausgeführt wird, da Windows keine Möglichkeit bietet, eine Verbindung zum Backend des Konsolengeräts herzustellen. Eine andere traditionelle Unix-Eingabe- / Ausgabemethode, ptys (Pseudo-Terminals), wird von Cygwin unterstützt, jedoch nicht vollständig von Windows. Das Grundproblem besteht darin, dass eine Cygwin-Pty eine Pipe ist und es einigen Windows-Anwendungen nicht gefällt, wenn ihre Eingabe oder Ausgabe an Pipes umgeleitet wird.

Ich habe ein kleines C-Programm geschrieben, das ich unter Windows mit VC ++ 's cl.exe kompiliert habe -

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

Wenn ich das Cygwin-Terminal ( mintty.exe ) starte und dieses Programm starte , kann ich nicht damit interagieren.

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

^ - keine Antwort

Aber wenn ich es in eine Pfeife stecke, funktioniert es -

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

Grundsätzlich kann es nicht mit dem Terminal mintty.exe interagieren . Wenn Sie jedoch bash.exe direkt von einer Windows-Konsole aus ausführen , kann die Interaktion korrekt erfolgen mit:

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

Ich dachte dann, wenn ich in meinen Computer ssh und dieses Programm als Befehl ausführen würde, würde es funktionieren, als würde das Terminal nicht direkt damit interagieren, aber der SSH-Server wird. Aber das geht auch nicht -

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

^ - keine Antwort

Aber das in eine Pfeife zu stecken funktioniert wieder! -

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

Könnte jemand die Theorie hinter all diesen Beobachtungen erklären?

Ist die Interaktion zwischen dem Terminal und der Shell mehr als nur die Verwendung von stdin , stdout und stderr der Shell ?

Wie unterscheidet sich die Windows-Konsole? Warum scheinen die Windows-Konsolenprogramme in einer Pipeline mit den Cygwin-Programmen gut zu funktionieren?

0cd
quelle

Antworten:

3

Wenn Sie fflush(stdout)zu Ihrer whileSchleife (nach printf) hinzufügen , funktioniert Ihr Programm wie erwartet, auch innerhalb von Mintty. Sie sollten auch in der Lage sein, setbuf(stdout, NULL)als erste Operation stdout aufzurufen und diese Funktion auszuführen.

Sie können auch c: \ cygwin \ bin \ bash in Ihrem Windows-Konsolenfenster ausführen, und Ihr ursprüngliches Programm wird so funktionieren, wie Sie es möchten. Ich habe es nicht ausprobiert, aber Sie sollten auch in der Lage sein, Bash in einem Conemu- oder Console2-Fenster auszuführen und Ihr ursprüngliches Programm wie erwartet arbeiten zu lassen.

Das heißt: es geht um die Minze.

Hier ist (ein Teil davon), was los ist:

Die Windows-Konsole ist etwas ganz Besonderes. Windows hat einen Dienst namens Client / Server Runtime Subsystem. Wenn Sie eine Befehlszeile auf Windows starten, was Sie tatsächlich tun , ist die Verbindung mit dem Client / Server - Runtime - Subsystem, und es ist für Sie das Fenster zu schaffen.

Mintty hingegen ist ein "normales" Fenster (das zufällig einen Terminal-Emulator ausführt).

Die I / O-Routinen der Microsoft C-Bibliothek testen tatsächlich, ob sie in einem vom Client / Server-Laufzeitsubsystem erstellten Fenster ausgeführt werden, und ändern gegebenenfalls ihr Verhalten. Eine Änderung, die sie vornehmen, besteht darin, die vollständige Pufferung für stdout zu deaktivieren.

Wenn Sie unter Mintty laufen, denken die Gets / Puts-Routinen des Fensters, dass sie nicht in einer Eingabeaufforderung ausgeführt werden, und führen daher eine vollständige Pufferung durch.

Hier ist noch ein Trick: Unter bashLaufen minttykann man laufen cat | echo1.exe. Geben Sie dann ein paar Dinge ein, und wenn Sie ^Dalle gepufferten stdout-Ausgaben treffen, werden sie alle auf einmal angezeigt.

Der Grund, warum der cat | echo1.exeTrick funktioniert, ist, dass cates sich um ein Cygwin-Programm handelt. Cygwin ist im Grunde genommen eine Posix-Emulationsbibliothek. Das stdinof catwird also von der Cygwin-Bibliothek emuliert, und die Cygwin-Bibliothek wird ^Danders behandelt als ein "richtiger" Windows-Standard.

Wenn Sie jedoch nur echo1.exeunter " bashunder" laufen, werden minttyIhre Tastatureingaben in einen nicht emulierten Dateistream übertragen (dh Ihre stdin ist eine echte Windows-stdin, nicht eine, die von der Cygwin-Bibliothek emuliert wurde), sodass ^Dkein eof gesendet wird. ^ZWürde stattdessen eof senden, ^Zbedeutet aber etwas Besonderes, damit es nicht gesendet wird. Vielmehr müssen Sie treffen, ^Cwas echo1.exesofort beendet wird (und die Puffer nicht leeren, was korrekt ist.)

Wandering Logic
quelle
Danke für deine Antwort! Ausgabepufferung erklärt viel! Könnten Sie etwas näher erläutern, warum der ^Dnicht erreicht wird echo1.exeund was ein nicht emulierter Dateistream ist?
03.05.13
Ich habe gerade einige Änderungen vorgenommen (letzte 2 Absätze). Erklärt das die Emulation / Nicht-Emulation besser?
Wandering Logic
danke, das macht es klarer! Ich bin immer noch neugierig, wie bash das ^ Z erfasst. Läuft das DOS-Programm nicht im Vordergrund?
07.05.13
Ich komme hier aus meiner Tiefe. Ich vermute, dass Mintty das ^ Z einfängt und es (irgendwie) anstelle des Vordergrundprogramms an Bash weitergibt. Ich denke, das ist irgendwie ein Teil der Art und Weise, wie Mintty und Cygwin den Begriff eines Unix-Tty emulieren. Wenn Sie bash unter einem Fenster laufen trösten die ^ Z nicht in den Vordergrund Programm gehen.
Wandering Logic