Como posso verificar se o meu shell está sendo executado em um terminal?

20

Eu quero executar alguma ação somente se meu shell estiver "conectado" a um terminal, ou seja, somente 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) seja impressa / ecoado para um terminal.

Como posso fazer isso, sem depender de especificações do GNU / Linux (como /proc/self ) diretamente?

    
por einpoklum 01.11.2017 / 23:16

3 respostas

29

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

-t file_descriptor

True if file descriptor number file_descriptor is open and is associated with a terminal. False if file_descriptor is not a valid file descriptor number, or if file descriptor number file_descriptor is not open, or if it is open but is not associated with a terminal.

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

test -t 0

Você pode fazer o mesmo para os 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 retorna 0 (sucede) se os descritores estiverem conectados a um terminal e for falso de outra forma.

test também está disponível como o comando [ para um "teste de colchetes":

 if [ -t 0 ] ; then ...

é uma maneira idiomática de escrever esta condição.

    
por 01.11.2017 / 23:27
8

Eu imagino que isso seja uma duplicata, mas não consigo encontrá-lo. Use

[ -t 0 ]

e

[ -t 1 ]

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

    
por 01.11.2017 / 23:26
6

Apenas uma nota extra em cima das respostas que já foram dadas. Observe que [ -t 0 ] testa que o descritor de arquivo 0 está aberto em 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 há 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 a maioria dos que você gosta, isso é bom o suficiente uma 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, pode-se fazer:

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

Para alimentar o que recebeu por RS232 em myscript .

echo test | ssh -tt host myscript

teria o stdin de myscript sendo um dispositivo pty (com sshd na outra extremidade e, eventualmente (através da conexão ssh), não um terminal, mas um cano alimentado por echo )

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

printf >&0 '\e[5n'

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

Agora, há vários problemas com isso, então eu não recomendaria fazer isso, exceto no caso em que você deseja verificar isso porque deseja executar um aplicativo visual da TUI (nesse caso, seria melhor usar bibliotecas como ncurses e, em vez do DSR, você preferiria enviar uma seqüência de escape de identificação de 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 foi aberto no modo somente leitura, o que faria com que printf falhasse, mas no caso de stdin ser um dispositivo tty aberto no modo de leitura + gravação, isso terá o efeito colateral de enviar essa sequência para o outro lado. Por exemplo, no nosso exemplo ssh acima, isso realmente enviará a sequência para um terminal (mas a resposta não será recebida no stdin)
  • É difícil ler a resposta de forma confiável e portável. Você precisaria alterar temporariamente a disciplina de 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ê desistirá e decidirá que não há terminal. Se você quiser considerar as pessoas discando em conexões via satélite, isso significa um longo tempo limite.
  • A leitura de um terminal em segundo plano suspenderia seu script com um sinal SIGTTIN.
por 02.11.2017 / 11:09