Como detectar de dentro de um script de shell se sua saída padrão está sendo enviada para um terminal ou se é canalizada para outro processo?
O caso em questão: eu gostaria de adicionar códigos de escape para colorir a saída, mas apenas quando executados de forma interativa, mas não quando canalizados, semelhante ao que ls --color
faz.
Respostas:
Em um shell POSIX puro,
retorna "terminal", porque a saída é enviada ao seu terminal, enquanto
retorna "não um terminal", porque a saída do parêntese é canalizada para
cat
.O
-t
sinalizador é descrito nas páginas do manual como... onde
fd
pode ser uma das atribuições usuais de descritor de arquivo:fonte
-t
sinalizador é especificado no POSIX e, portanto, deve funcionar para qualquer shell compatível com o POSIX (ou seja, não é uma extensão do bash). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfish
resposta concha. O usotest
é legal, mas não posso tentar o exemplo entre parênteses, pois isso não é suportado. Tentei agrupá-lo de forma análogabegin; ...; end
, mas isso não pareceu funcionar e apenas executei o bloco de código positivo novamente. Achei que talvezstatus
fosse necessário usar, mas isso não parece verificar a tubulação. Acho que quero essencialmente verificar se o STDOUT de um comando / script anterior não está definido para o terminal, graças a essas respostas esclarecedoras.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:
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: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 dessh
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ãossh
estar sendo usado TTY ou forçado :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:
stat
descritores de arquivo / dev / stdin[[ "${-}" =~ 'i' ]]
tty
etty -s
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.
fonte
stat
chamada em / dev / stdin. E por que funciona"${-}"
outty -s
não? Eu também procurei no código fonte,cat
mas não consigo ver qual parte está fazendo a mágica que você não pode fazer no shell POSIX. Você poderia expandir isso?O comando
test
(embutidobash
), tem uma opção para verificar se um descritor de arquivo é um tty.Veja "
man test
" ou "man bash
" e procure por "-t
"fonte
help test
(ehelp help
para mais) e, em seguida,info bash
para informações mais detalhadas. Esses comandos são ótimos se você acabar criando scripts offline ou quiser apenas obter um entendimento mais amplo.Você não menciona qual shell está usando, mas no Bash, você pode fazer isso:
fonte
No Solaris, a sugestão de Dejay Clayton funciona principalmente. O -p não responde conforme desejado.
bash_redir_test.sh se parece com:
No Linux, funciona muito bem:
No Solaris:
fonte
O código a seguir (testado apenas no linux bash 4.4) não deve ser considerado portátil nem recomendado , mas por uma questão de integridade, aqui está:
Não sei por que, mas parece que o descritor de arquivo "3" é criado de alguma forma quando uma função bash tem STDIN canalizado.
Espero que ajude,
fonte