No hay una forma infalible de determinar si STDIN, STDOUT o STDERR se están canalizando hacia / desde su script, principalmente debido a programas como ssh
.
Cosas que "normalmente" funcionan
Por ejemplo, la siguiente solución bash funciona correctamente en un shell interactivo:
[[ -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'
Pero no siempre funcionan
Sin embargo, al ejecutar este comando como un comando que no es TTY ssh
, las transmisiones STD siempre parecen estar siendo canalizadas. Para demostrar esto, use STDIN porque es más fácil:
# 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 ${?}'
Por que es importante
Este es un gran problema, porque implica que no hay forma de que un script bash sepa si un ssh
comando que no es tty se está canalizando o no. Tenga en cuenta que este comportamiento desafortunado se introdujo cuando las versiones recientes de ssh
comenzaron a utilizar tuberías para STDIO no TTY. Las versiones anteriores usaban sockets, que PODRÍAN diferenciarse desde dentro de bash usando [[ -S ]]
.
Cuando importa
Esta limitación normalmente causa problemas cuando desea escribir un script bash que tenga un comportamiento similar a una utilidad compilada, como cat
. Por ejemplo, cat
permite el siguiente comportamiento flexible en el manejo de varias fuentes de entrada simultáneamente, y es lo suficientemente inteligente como para determinar si está recibiendo una entrada canalizada independientemente de si ssh
se está utilizando TTY no forzado o TTY forzado :
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Solo puede hacer algo así si puede determinar de manera confiable si las tuberías están involucradas o no. De lo contrario, la ejecución de un comando que lee STDIN cuando no hay entrada disponible desde cualquiera de las tuberías o la redirección dará como resultado que el script se cuelgue y espere la entrada de STDIN.
Otras cosas que no funcionan
Al tratar de resolver este problema, he examinado varias técnicas que no logran resolverlo, incluidas las que incluyen:
- examinar las variables de entorno SSH
- utilizando
stat
descriptores de archivo on / dev / stdin
- examinar el modo interactivo a través de
[[ "${-}" =~ 'i' ]]
- examinar el estado de tty a través de
tty
ytty -s
- examinar el
ssh
estado a través de[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Tenga en cuenta que si está utilizando un sistema operativo que admite el /proc
sistema de archivos virtual, es posible que tenga suerte siguiendo los enlaces simbólicos de STDIO para determinar si se está utilizando una tubería o no. Sin embargo, /proc
no es una solución multiplataforma compatible con POSIX.
Soy extremadamente interesante para resolver este problema, así que avíseme si piensa en alguna otra técnica que pueda funcionar, preferiblemente soluciones basadas en POSIX que funcionen tanto en Linux como en BSD.