Il n'existe aucun moyen infaillible de déterminer si STDIN, STDOUT ou STDERR sont dirigés vers / depuis votre script, principalement à cause de programmes comme ssh
.
Choses qui fonctionnent «normalement»
Par exemple, la solution bash suivante fonctionne correctement dans un shell interactif:
[[ -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'
Mais ils ne fonctionnent pas toujours
Cependant, lors de l'exécution de cette commande en tant que commande non TTY ssh
, les flux STD semblent toujours être acheminés. Pour le démontrer, utilisez STDIN car c'est plus simple:
# 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 ${?}'
Pourquoi est-ce important
C'est un gros problème, car cela implique qu'il n'y a aucun moyen pour un script bash de dire si une ssh
commande non tty est envoyée ou non. Notez que ce comportement malheureux a été introduit lorsque des versions récentes de ont ssh
commencé à utiliser des canaux pour les non-TTY STDIO. Les versions précédentes utilisaient des sockets, qui POURRAIENT être différenciés de bash en utilisant [[ -S ]]
.
Quand c'est important
Cette limitation pose normalement des problèmes lorsque vous souhaitez écrire un script bash qui a un comportement similaire à un utilitaire compilé, tel que cat
. Par exemple, cat
permet le comportement flexible suivant dans la gestion simultanée de diverses sources d'entrée et est suffisamment intelligent pour déterminer s'il reçoit une entrée canalisée, que l' ssh
on utilise ou non un ATS forcé :
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Vous ne pouvez faire quelque chose comme ça que si vous pouvez déterminer de manière fiable si des tuyaux sont impliqués ou non. Sinon, l'exécution d'une commande qui lit STDIN lorsqu'aucune entrée n'est disponible à partir des canaux ou de la redirection entraîne le blocage du script et l'attente de l'entrée STDIN.
D'autres choses qui ne fonctionnent pas
En essayant de résoudre ce problème, j'ai examiné plusieurs techniques qui ne parviennent pas à résoudre le problème, y compris celles qui impliquent:
- examen des variables d'environnement SSH
- utilisation
stat
de descripteurs de fichiers on / dev / stdin
- examen du mode interactif via
[[ "${-}" =~ 'i' ]]
- examen du statut tty via
tty
ettty -s
- examen du
ssh
statut via[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Notez que si vous utilisez un système d'exploitation qui prend en charge le /proc
système de fichiers virtuel, vous aurez peut-être de la chance en suivant les liens symboliques de STDIO pour déterminer si un canal est utilisé ou non. Cependant, il /proc
ne s'agit pas d'une solution multiplateforme compatible POSIX.
Je suis extrêmement intéressé à résoudre ce problème, alors faites-moi savoir si vous pensez à une autre technique qui pourrait fonctionner, de préférence des solutions basées sur POSIX qui fonctionnent à la fois sur Linux et BSD.