Não há uma maneira infalível de determinar se STDIN, STDOUT ou STDERR estão sendo canalizados para / do seu script, principalmente por causa de programas como o ssh
.
Coisas que "normalmente" funcionam
Por exemplo, a seguinte solução do bash funciona corretamente em um shell interativo:
[[ -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'
Mas eles nem sempre funcionam
No entanto, ao executar este comando como um comando não-TTY ssh
, os fluxos STD sempre parecem estar sendo canalizados. Para demonstrar isso, use STDIN porque é mais 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 isso importa
Isso é muito importante, porque implica que não há como um script bash dizer se um ssh
comando não-tty está sendo canalizado ou não. Observe que esse comportamento infeliz foi introduzido quando versões recentes de ssh
começaram a usar pipes para STDIO não-TTY. As versões anteriores usavam soquetes, que PODEM ser diferenciados de dentro do bash usando [[ -S ]]
.
Quando importa
Essa limitação normalmente causa problemas quando você deseja escrever um script bash com comportamento semelhante a um utilitário compilado, como cat
. Por exemplo, cat
permite o seguinte comportamento flexível ao lidar com várias fontes de entrada simultaneamente e é inteligente o suficiente para determinar se está recebendo entrada canalizada, independentemente de não ssh
estar sendo usado TTY ou forçado :
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Você só pode fazer algo assim se puder determinar com segurança se os tubos estão envolvidos ou não. Caso contrário, a execução de um comando que lê STDIN quando nenhuma entrada está disponível nos pipes ou redirecionamentos resultará na interrupção do script e na espera pela entrada STDIN.
Outras coisas que não funcionam
Ao tentar resolver esse problema, observei várias técnicas que não conseguem resolver o problema, incluindo aquelas que envolvem:
- examinando variáveis de ambiente SSH
- usando
stat
descritores de arquivo / dev / stdin
- examinando o modo interativo via
[[ "${-}" =~ 'i' ]]
- examinando o status tty via
tty
etty -s
- examinando o
ssh
status via[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Observe que, se você estiver usando um sistema operacional compatível com o /proc
sistema de arquivos virtual, poderá ter sorte seguindo os links simbólicos do STDIO para determinar se um pipe está sendo usado ou não. No entanto, /proc
não é uma solução compatível com POSIX multiplataforma.
Eu sou extremamente interessante na solução desse problema, então, deixe-me saber se você pensa em alguma outra técnica que possa funcionar, de preferência soluções baseadas em POSIX que funcionem no Linux e no BSD.