Como verifico se meu shell está sendo executado em um terminal?

22

Eu quero executar alguma ação apenas se meu shell estiver "conectado" a um terminal, ou seja, apenas se minha entrada padrão vier da entrada de um terminal e minha saída padrão (e erro padrão? Talvez isso não importe) for impressa / ecoada para um terminal.

Como posso fazer isso, sem depender /proc/selfdiretamente das especificidades do GNU / Linux (como )?

einpoklum - restabelece Monica
fonte
Similar: unix.stackexchange.com/q/22162/117549
Jeff Schaller

Respostas:

33

isattyé uma função para verificar isso , e a -tbandeira do testcomando torna isso acessível a partir de um script de shell:

-t file_descriptor

Verdadeiro se o número do descritor de arquivo file_descriptor estiver aberto e estiver associado a um terminal. False se file_descriptor não for um número válido de descritor de arquivo, ou se o número do descritor de arquivo file_descriptor não estiver aberto, ou se estiver aberto, mas não estiver associado a um terminal.

Você pode verificar se FD 0 (entrada padrão) é um TTY com:

test -t 0

Você pode fazer o mesmo nos FDs 1 e 2 para verificar os fluxos de saída e erro, ou todos eles:

test -t 0 -a -t 1 -a -t 2

O comando retornará 0 (êxito) se os descritores estiverem conectados a um terminal e, caso contrário, será falso.

testtambém está disponível como o [comando para um "teste de suporte":

 if [ -t 0 ] ; then ...

é uma maneira idiomática de escrever isso condicional.

Michael Homer
fonte
8

Imagino que seja uma duplicata, mas não consigo encontrá-la. Usar

[ -t 0 ]

e

[ -t 1 ]

para testar respectivamente se a entrada e a saída padrão estão conectadas a um terminal. man testtem os detalhes.

Stephen Kitt
fonte
7

Apenas uma nota extra sobre as respostas finas que já foram dadas. Observe que [ -t 0 ]testa se o descritor de arquivo 0 está aberto, um arquivo que é um arquivo de dispositivo com uma disciplina de linha tty (normalmente, isso é feito verificando se um termo inofensivo ioctl () é bem-sucedido).

Além disso, isso não significa necessariamente que exista um terminal ou emulador de terminal (com um usuário real digitando em um teclado) do outro lado (embora na imensa maioria dos casos e provavelmente na maioria dos que você se importa, isso é bom o suficiente). aproximação).

Os dispositivos tty e pty também podem ser usados ​​para transferência de dados ou como um mecanismo de comunicação entre processos.

Por exemplo, alguém poderia fazer:

(stty raw -echo; myscript) < /dev/ttyS0

Para alimentar o que é recebido pelo RS232 para myscript.

echo test | ssh -tt host myscript

teria myscriptde ser um dispositivo de entrada padrão Pty (com sshd, na outra extremidade, e, eventualmente, (através da ligação ssh) não um terminal, mas um tubo alimentado por echo)

Para verificar ainda mais se existe um terminal na outra extremidade da linha ou pty RS232, você também pode verificar se uma $TERMvariável está definida e não-vazia ( [ -n "$TERM" ]) e enviar uma sequência de escape do Relatório de status do dispositivo sobre esse fd e verificar se você recebe uma resposta (além de [ -t 0 ]e [ -n "$TERM" ]).

printf >&0 '\e[5n'

É respondido com um \e[0npela maioria dos terminais.

Agora, existem vários problemas com isso, então eu não recomendaria fazer isso, exceto no caso em que você deseja verificar porque deseja executar um aplicativo TUI visual (nesse caso, seria melhor usar bibliotecas como ncurses, e, em vez do DSR, você deseja enviar uma sequência de escape de identificação do dispositivo para consultar o tipo de terminal com mais precisão do que via $TERM):

  • Felizmente, na maioria dos casos em que stdin não é um terminal, ele será aberto no modo somente leitura, o que causaria printffalha, mas no caso de o stdin ser um dispositivo tty aberto no modo leitura + gravação, isso terá o efeito colateral de enviar essa sequência para o outro lado. Por exemplo, em nosso exemplo ssh acima, isso realmente enviará a sequência para um terminal (mas a resposta não será apresentada no stdin)
  • É difícil ler a resposta de forma confiável e portável. Você precisaria alterar temporariamente a disciplina da linha tty e ler um byte de cada vez. Você também precisará decidir um tempo limite pelo qual, se a resposta não for vista, você desiste e decide que não há terminal. Se você quiser considerar as pessoas discando através de conexões via satélite, isso significa um longo tempo limite.
  • A leitura de um terminal quando em segundo plano suspende seu script com um sinal SIGTTIN.
Stéphane Chazelas
fonte