Wie erkenne ich in einem Shell-Skript, ob seine Standardausgabe an ein Terminal gesendet oder an einen anderen Prozess weitergeleitet wird?
Das Beispiel: Ich möchte Escape-Codes hinzufügen, um die Ausgabe einzufärben, aber nur, wenn sie interaktiv ausgeführt werden, aber nicht, wenn sie weitergeleitet werden, ähnlich wie dies der ls --color
Fall ist.
Antworten:
In einer reinen POSIX-Shell
Gibt "Terminal" zurück, da die Ausgabe an Ihr Terminal gesendet wird
Gibt "kein Terminal" zurück, da die Ausgabe der Klammer an weitergeleitet wird
cat
.Die
-t
Flagge wird in Manpages als beschrieben... wo
fd
kann eine der üblichen Dateideskriptorzuweisungen sein:quelle
-t
Flag in POSIX angegeben und sollte daher für jede POSIX-kompatible Shell funktionieren (dh es ist keine Bash-Erweiterung). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfish
Shell-Antwort. Die Verwendungtest
ist ordentlich, aber ich kann das Beispiel in Klammern nicht ausprobieren, da dies nicht unterstützt wird. Ich habe versucht, es analog zu verpackenbegin; ...; end
, aber das schien nicht zu funktionieren, und habe den positiven Codeblock einfach erneut ausgeführt. Ich dachte, ich müsste es vielleicht benutzen,status
aber das scheint nicht nach Rohrleitungen zu suchen. Ich denke, ich möchte im Wesentlichen überprüfen, ob STDOUT eines vorhergehenden Befehls / Skripts dank dieser klarstellenden Antworten nicht auf das Terminal eingestellt ist.Es gibt keine narrensichere Methode, um festzustellen, ob STDIN, STDOUT oder STDERR zu / von Ihrem Skript geleitet werden, hauptsächlich aufgrund von Programmen wie
ssh
.Dinge, die "normal" funktionieren
Die folgende Bash-Lösung funktioniert beispielsweise in einer interaktiven Shell ordnungsgemäß:
Aber sie funktionieren nicht immer
Wenn Sie diesen Befehl jedoch als Nicht-TTY-
ssh
Befehl ausführen , sehen STD-Streams immer so aus, als würden sie weitergeleitet. Um dies zu demonstrieren, verwenden Sie STDIN, weil es einfacher ist:Warum es wichtig ist
Dies ist eine ziemlich große Sache, da es impliziert, dass ein Bash-Skript nicht erkennen kann, ob ein Nicht-Tty-
ssh
Befehl weitergeleitet wird oder nicht. Beachten Sie, dass dieses unglückliche Verhalten eingeführt wurde, als neuere Versionen vonssh
Pipes für Nicht-TTY-STDIO verwendet wurden. In früheren Versionen wurden Sockets verwendet, die durch Verwendung von Bash innerhalb von Bash unterschieden werden KÖNNTEN[[ -S ]]
.Wenn es darauf ankommt
Diese Einschränkung verursacht normalerweise Probleme, wenn Sie ein Bash-Skript schreiben möchten, dessen Verhalten einem kompilierten Dienstprogramm ähnelt, z
cat
. Zum Beispielcat
ermöglicht es die folgenden flexible Verhalten gleichzeitig verschiedene Eingangsquellen in der Handhabung und ist intelligent genug , um zu bestimmen , ob es verrohrt Eingang unabhängig davon empfängt , ob nicht-TTY TTY oder Zwangssh
verwendet wird:Sie können so etwas nur tun, wenn Sie zuverlässig feststellen können, ob Rohre betroffen sind oder nicht. Andernfalls führt das Ausführen eines Befehls, der STDIN liest, wenn keine Eingabe von Pipes oder Umleitungen verfügbar ist, dazu, dass das Skript hängt und auf die STDIN-Eingabe wartet.
Andere Dinge, die nicht funktionieren
Bei dem Versuch, dieses Problem zu lösen, habe ich mir verschiedene Techniken angesehen, die das Problem nicht lösen können, einschließlich solcher, die Folgendes umfassen:
stat
von Dateideskriptoren für / dev / stdin[[ "${-}" =~ 'i' ]]
tty
undtty -s
ssh
Status prüfen über[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Beachten Sie, dass
/proc
Sie möglicherweise Glück haben , wenn Sie ein Betriebssystem verwenden, das das virtuelle Dateisystem unterstützt, indem Sie den symbolischen Links für STDIO folgen, um festzustellen, ob eine Pipe verwendet wird oder nicht. Es handelt sich jedoch/proc
nicht um eine plattformübergreifende POSIX-kompatible Lösung.Ich bin äußerst interessant bei der Lösung dieses Problems. Lassen Sie mich wissen, wenn Sie an eine andere Technik denken, die möglicherweise funktioniert, vorzugsweise POSIX-basierte Lösungen, die sowohl unter Linux als auch unter BSD funktionieren.
quelle
stat
Aufrufs von / dev / stdin. Und warum funktioniert"${-}"
odertty -s
nicht? Ich habe mir auch den Quellcode von angesehen,cat
aber nicht gesehen, welcher Teil dort die Magie ausübt, die Sie in der POSIX-Shell nicht ausführen können. Könntest du das weiter erläutern?Der Befehl
test
(integriertbash
) bietet eine Option zum Überprüfen, ob ein Dateideskriptor ein tty ist.Siehe "
man test
" oder "man bash
" und suchen Sie nach "-t
"quelle
help test
(undhelp help
für mehr), danninfo bash
für detailliertere Informationen. Diese Befehle eignen sich hervorragend, wenn Sie jemals offline Skripte erstellen oder einfach nur ein umfassenderes Verständnis erlangen möchten.Sie erwähnen nicht, welche Shell Sie verwenden, aber in Bash können Sie dies tun:
quelle
Unter Solaris funktioniert der Vorschlag von Dejay Clayton hauptsächlich. Das -p reagiert nicht wie gewünscht.
bash_redir_test.sh sieht aus wie:
Unter Linux funktioniert es hervorragend:
Unter Solaris:
quelle
Der folgende Code (nur in Linux Bash 4.4 getestet) sollte weder als portabel angesehen noch empfohlen werden. Der Vollständigkeit halber ist er jedoch hier:
Ich weiß nicht warum, aber es scheint, dass der Dateideskriptor "3" irgendwie erstellt wird, wenn eine Bash-Funktion STDIN-Piping hat.
Ich hoffe es hilft,
quelle