¿Cómo verifico si mi shell se está ejecutando en una terminal?

22

Quiero realizar alguna acción solo si mi shell está "conectado" a un terminal, es decir, solo si mi entrada estándar proviene de la entrada de un terminal y mi salida estándar (¿y error estándar? Quizás eso no importa) se imprime / repite una terminal

¿Cómo puedo hacer eso, sin depender /proc/selfdirectamente de los detalles de GNU / Linux (como )?

einpoklum - reinstalar a Monica
fuente
Similar: unix.stackexchange.com/q/22162/117549
Jeff Schaller

Respuestas:

33

isattyes una función para verificar esto , y la -tbandera del testcomando lo hace accesible desde un script de shell:

-t descriptor_archivo

Verdadero si el número de descriptor de archivo file_descriptor está abierto y está asociado con un terminal. Falso si file_descriptor no es un número de descriptor de archivo válido, o si el número de descriptor de archivo file_descriptor no está abierto, o si está abierto pero no está asociado con un terminal.

Puede verificar si FD 0 (entrada estándar) es un TTY con:

test -t 0

Puede hacer lo mismo para los FD 1 y 2 para verificar los flujos de salida y error, o todos ellos:

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

El comando devuelve 0 (tiene éxito) si los descriptores están conectados a una terminal y, de lo contrario, es falso.

testtambién está disponible como [comando para una "prueba de soporte":

 if [ -t 0 ] ; then ...

es una forma idiomática de escribir este condicional.

Michael Homer
fuente
8

Me imagino que esto es un duplicado, pero no puedo encontrarlo. Utilizar

[ -t 0 ]

y

[ -t 1 ]

para probar respectivamente si la entrada y la salida estándar están conectadas a un terminal. man testTiene los detalles.

Stephen Kitt
fuente
7

Solo una nota adicional sobre las buenas respuestas que ya se han dado. Tenga en cuenta que [ -t 0 ]prueba que el descriptor de archivo 0 está abierto, un archivo que es un archivo de dispositivo con una disciplina de línea tty (por lo general, esto se realiza al verificar que un termio (s) inofensivo ioctl () tenga éxito).

Además, eso no significa necesariamente que haya un terminal o emulador de terminal (con un usuario real escribiendo en un teclado) en el otro extremo (aunque en la inmensa mayoría de los casos y probablemente en la mayoría de los que le interesan, eso es bastante bueno y aproximación).

Los dispositivos tty y pty también se pueden usar para la transferencia de datos o como un mecanismo de comunicación entre procesos.

Por ejemplo, uno podría hacer:

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

Para alimentar lo recibido a través de RS232 a myscript.

echo test | ssh -tt host myscript

tendría myscriptstdin siendo un dispositivo pty (con sshdel otro extremo, y eventualmente (a través de la conexión ssh) no un terminal, sino una tubería alimentada por echo)

Para verificar aún más que hay un terminal en el otro extremo de esa línea o pty RS232, también puede verificar que una $TERMvariable esté configurada y no vacía ( [ -n "$TERM" ]) y enviar una secuencia de escape del Informe de estado del dispositivo sobre ese fd y verificar que reciba una respuesta (además de la [ -t 0 ]y [ -n "$TERM" ]).

printf >&0 '\e[5n'

Se responde con un \e[0npor la mayoría de las terminales.

Ahora hay varios problemas con eso, por lo que no recomendaría hacerlo, excepto en el caso en que desee verificar eso porque desea ejecutar una aplicación visual TUI (en cuyo caso, sería mejor usar bibliotecas como ncurses, y en lugar del DSR, preferiría enviar una secuencia de escape de identificación del dispositivo para consultar el tipo de terminal con mayor precisión que a través de $TERM):

  • Afortunadamente, en la mayoría de los casos en que stdin no es un terminal, habrá estado abierto en modo de solo lectura, lo que provocaría que printffallara, pero en caso de que stdin sea un dispositivo tty abierto en modo de lectura + escritura, tendrá el efecto secundario de enviar esa secuencia al otro extremo. Por ejemplo, en nuestro ejemplo ssh anterior, eso enviará la secuencia a un terminal (pero la respuesta no llegará en stdin)
  • Es difícil leer la respuesta de manera confiable y portátil. Debería cambiar la disciplina de la línea tty temporalmente y leer un byte a la vez. También tendrá que decidir un tiempo de espera por el cual, si no se ve la respuesta, se da por vencido y decide que no hay terminal. Si desea considerar a las personas que marcan a través de conexiones satelitales, eso significa un largo tiempo de espera.
  • Leer desde un terminal en segundo plano suspendería su secuencia de comandos con una señal SIGTTIN.
Stéphane Chazelas
fuente