Non esiste un modo infallibile per determinare se STDIN, STDOUT o STDERR vengono inviati al / dal tuo script, principalmente a causa di programmi come ssh
.
Cose che "normalmente" funzionano
Ad esempio, la seguente soluzione bash funziona correttamente in una shell interattiva:
[[ -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'
Ma non funzionano sempre
Tuttavia, quando si esegue questo comando come comando non TTY ssh
, i flussi STD sembrano sempre essere in fase di piping. Per dimostrarlo, utilizzare STDIN perché è più semplice:
# 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 ${?}'
Perchè importa
Questo è un grosso problema, perché implica che non c'è modo per uno script bash di dire se un ssh
comando non tty viene inviato o meno. Si noti che questo sfortunato comportamento è stato introdotto quando le versioni recenti di hanno ssh
iniziato a utilizzare pipe per STDIO non TTY. Le versioni precedenti utilizzavano socket, che POTREBBE essere differenziati all'interno di bash utilizzando [[ -S ]]
.
Quando conta
Questa limitazione normalmente causa problemi quando si desidera scrivere uno script bash con un comportamento simile a un'utilità compilata, ad esempio cat
. Ad esempio, cat
consente il seguente comportamento flessibile nella gestione simultanea di varie origini di input ed è abbastanza intelligente da determinare se sta ricevendo input di pipeline indipendentemente dal fatto che ssh
venga utilizzato non-TTY o forzato-TTY :
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Puoi fare qualcosa del genere solo se riesci a determinare in modo affidabile se i tubi sono coinvolti o meno. Altrimenti, l'esecuzione di un comando che legge STDIN quando non è disponibile alcun input da entrambe le pipe o il reindirizzamento comporterà la sospensione dello script e l'attesa dell'input STDIN.
Altre cose che non funzionano
Nel tentativo di risolvere questo problema, ho esaminato diverse tecniche che non riescono a risolvere il problema, comprese quelle che coinvolgono:
- esaminando le variabili di ambiente SSH
- usando
stat
i descrittori di file su / dev / stdin
- esaminando la modalità interattiva tramite
[[ "${-}" =~ 'i' ]]
- esaminando lo stato tty tramite
tty
etty -s
- esame dello
ssh
stato tramite[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Si noti che se si utilizza un sistema operativo che supporta il /proc
filesystem virtuale, si potrebbe avere fortuna seguendo i collegamenti simbolici per STDIO per determinare se una pipe viene utilizzata o meno. Tuttavia, /proc
non è una soluzione multipiattaforma compatibile con POSIX.
Sono estremamente interessante nel risolvere questo problema, quindi per favore fatemi sapere se pensate a qualsiasi altra tecnica che potrebbe funzionare, preferibilmente soluzioni basate su POSIX che funzionano sia su Linux che su BSD.