Wie überprüfe ich, ob meine Shell in einem Terminal ausgeführt wird?

22

Ich möchte nur dann eine Aktion ausführen, wenn meine Shell mit einem Terminal "verbunden" ist, dh nur dann, wenn meine Standardeingabe von der Eingabe eines Terminals stammt und meine Standardausgabe (und mein Standardfehler? Vielleicht spielt das keine Rolle) gedruckt wird ein Terminal.

Wie kann ich das tun, ohne mich /proc/selfdirekt auf GNU / Linux-Besonderheiten (wie ) zu verlassen?

einpoklum - Monica wieder einsetzen
quelle
Ähnlich: unix.stackexchange.com/q/22162/117549
Jeff Schaller

Antworten:

33

isattyist eine Funktion, um dies zu überprüfen , und das -tFlag des testBefehls macht dies über ein Shell-Skript zugänglich:

-t Dateideskriptor

True, wenn die Dateideskriptornummer file_descriptor geöffnet ist und einem Terminal zugeordnet ist. False, wenn file_descriptor keine gültige Dateideskriptornummer ist oder wenn file_descriptor nicht geöffnet ist oder wenn es geöffnet ist, aber keinem Terminal zugeordnet ist.

Sie können überprüfen, ob FD 0 (Standardeingabe) ein TTY ist:

test -t 0

Sie können das Gleiche für FDs 1 und 2 tun, um die Ausgabe- und Fehlerströme oder alle zu überprüfen:

test -t 0 -a -t 1 -a -t 2

Der Befehl gibt 0 zurück (erfolgreich), wenn die Deskriptoren an ein Terminal angeschlossen sind, und ist ansonsten falsch.

teststeht auch als [Befehl für einen "Bracket-Test" zur Verfügung:

 if [ -t 0 ] ; then ...

ist eine idiomatische Möglichkeit, diese Bedingung zu schreiben.

Michael Homer
quelle
8

Ich stelle mir vor, dass dies ein Duplikat ist, aber ich kann es nicht finden. Verwenden

[ -t 0 ]

und

[ -t 1 ]

um jeweils zu testen, ob Standardeingang und -ausgang an eine Klemme angeschlossen sind. man testhat die Details.

Stephen Kitt
quelle
7

Nur eine zusätzliche Anmerkung zu den bereits gegebenen guten Antworten. Beachten Sie, dass [ -t 0 ]überprüft wird, ob der Dateideskriptor 0 geöffnet ist. Dies ist eine Gerätedatei mit einer strengen Disziplin (in der Regel wird überprüft, ob ein harmloser Termio (s) ioctl () erfolgreich ist).

Das bedeutet auch nicht, dass es am anderen Ende ein Terminal oder einen Terminal-Emulator gibt (mit einem echten Benutzer, der auf einer Tastatur tippt) (obwohl dies in den meisten Fällen und wahrscheinlich auch in den meisten Fällen, die Sie interessieren, gut genug ist) Annäherung).

tty- und pty-Geräte können auch zur Datenübertragung oder als prozessübergreifender Kommunikationsmechanismus verwendet werden.

Zum Beispiel könnte man tun:

(stty raw -echo; myscript) < /dev/ttyS0

Um zu füttern, was über RS232 empfangen wird myscript.

echo test | ssh -tt host myscript

wäre myscriptstdin ein pty gerät (mit sshdam anderen ende und irgendwann (über die ssh verbindung) kein terminal sondern ein rohr gespeist durch echo)

Um weiter zu überprüfen, ob sich am anderen Ende der RS232-Leitung oder des Pty ein Terminal befindet, können Sie auch überprüfen, ob eine $TERMVariable gesetzt und nicht leer ist ( [ -n "$TERM" ]), und eine Escape-Sequenz für den Gerätestatusbericht über dieses FD senden und den Empfang überprüfen eine Antwort (zusätzlich zu [ -t 0 ]und [ -n "$TERM" ]).

printf >&0 '\e[5n'

Wird \e[0nvon den meisten Terminals mit einem beantwortet .

Nun gibt es mehrere Probleme mit diesem, so würde ich nicht tun , dass außer im Fall empfehlen , wo Sie überprüfen möchten, weil Sie eine visuelle TUI Anwendung ausgeführt werden soll (in diesem Fall, würden Sie besser dran , Bibliotheken wie ncurses, und anstatt des DSR möchten Sie lieber eine Geräteidentifikations-Escape-Sequenz senden, um den Terminaltyp genauer als über abzufragen $TERM:

  • Glücklicherweise war stdin in den meisten Fällen, in denen es sich nicht um ein Terminal handelt, im schreibgeschützten Modus geöffnet printf, was zu einem Fehlschlagen führen würde. Wenn stdin jedoch ein im Lese- / Schreibmodus geöffnetes tty-Gerät ist, hat dies den Nebeneffekt diese Sequenz an das andere Ende zu senden. Beispiel: In unserem obigen SSH-Beispiel wird die Sequenz tatsächlich an ein Terminal gesendet (aber die Antwort kommt nicht auf stdin).
  • Es ist schwer, die Antwort zuverlässig und tragbar zu lesen. Sie müssten die tty-Zeilendisziplin vorübergehend ändern und jeweils ein Byte lesen. Sie müssen auch eine Zeitüberschreitung festlegen, bei der Sie aufgeben, wenn die Antwort nicht angezeigt wird, und entscheiden, dass kein Terminal vorhanden ist. Wenn Sie in Betracht ziehen möchten, dass sich Personen über Satellitenverbindungen einwählen, bedeutet dies eine lange Zeitüberschreitung.
  • Wenn Sie im Hintergrund von einem Terminal aus lesen, wird Ihr Skript mit einem SIGTTIN-Signal angehalten.
Stéphane Chazelas
quelle