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äß:
[[ -t 1 ]] && \
echo 'STDOUT is attached to TTY'
[[ -p /dev/stdout ]] && \
echo 'STDOUT is attached to a pipe'
[[ ! -t 1 && ! -p /dev/stdout ]] && \
echo 'STDOUT is attached to a redirection'
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:
# CORRECT: Forced-tty mode correctly reports '1', which represents
# no pipe.
ssh -t localhost '[[ -p /dev/stdin ]]; echo ${?}'
# CORRECT: Issuing a piped command in forced-tty mode correctly
# reports '0', which represents a pipe.
ssh -t localhost 'echo hi | [[ -p /dev/stdin ]]; echo ${?}'
# INCORRECT: Non-tty mode reports '0', which represents a pipe,
# even though one isn't specified here.
ssh -T localhost '[[ -p /dev/stdin ]]; echo ${?}'
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 von ssh
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 Beispiel cat
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 Zwang ssh
verwendet wird:
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
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:
- Untersuchen von SSH-Umgebungsvariablen
- Verwenden
stat
von Dateideskriptoren für / dev / stdin
- Untersuchen des interaktiven Modus über
[[ "${-}" =~ 'i' ]]
- Prüfung des Status über
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.