scripts script resueltos programas programacion pasar parametros español ejercicios ejemplos comandos bash shell pipe

bash - programas - scripts linux ejercicios resueltos



¿Cómo detectar si mi shell script se está ejecutando a través de una tubería? (5)

El comando test (incorporado en bash ), tiene una opción para verificar si un descriptor de archivo es un tty.

if [ -t 1 ]; then # stdout is a tty fi

Consulte " man test " o " man bash " y busque " -t "

¿Cómo detecto desde un script de shell si su salida estándar se envía a un terminal o si se canaliza a otro proceso?

El caso en cuestión: me gustaría agregar códigos de escape para colorear la salida, pero solo cuando se ejecuta de manera interactiva, pero no cuando se canaliza, de manera similar a lo que hace ls --color .


En Solaris, la sugerencia de Dejay Clayton funciona principalmente. El -p no responde como se desea.

bash_redir_test.sh se ve como:

[[ -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''

En Linux, funciona muy bien:

:$ ./bash_redir_test.sh STDOUT is attached to TTY :$ ./bash_redir_test.sh | xargs echo STDOUT is attached to a pipe :$ rm bash_redir_test.log :$ ./bash_redir_test.sh >> bash_redir_test.log :$ tail bash_redir_test.log STDOUT is attached to a redirection

En Solaris:

:# ./bash_redir_test.sh STDOUT is attached to TTY :# ./bash_redir_test.sh | xargs echo STDOUT is attached to a redirection :# rm bash_redir_test.log bash_redir_test.log: No such file or directory :# ./bash_redir_test.sh >> bash_redir_test.log :# tail bash_redir_test.log STDOUT is attached to a redirection :#


En un shell POSIX puro,

if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi

devuelve "terminal", porque la salida se envía a su terminal, mientras que

(if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi) | cat

devuelve "no es un terminal", porque la salida de la paréntesis se canaliza a cat .

La bandera -t se describe en las páginas man como

-t fd Verdadero si el descriptor de archivos fd está abierto y se refiere a un terminal.

... donde fd puede ser una de las asignaciones habituales de descriptores de archivos:

0: stdin 1: stdout 2: stderr


No hay una manera infalible de determinar si STDIN, STDOUT o STDERR se canalizan a / desde su script, principalmente debido a programas como ssh .

Cosas que "normalmente" funcionan

Por ejemplo, la siguiente solución de bash funciona correctamente en un shell interactivo:

[[ -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''

Pero no siempre funcionan.

Sin embargo, cuando se ejecuta este comando como un comando ssh no es TTY, las secuencias STD siempre parecen estar siendo canalizadas. Para demostrar esto, usa STDIN porque es más 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 importa

Esto es bastante importante, porque implica que no hay forma de que un script bash diga si un comando ssh no-tty está siendo canalizado o no. Tenga en cuenta que este comportamiento desafortunado se introdujo cuando las versiones recientes de ssh comenzaron a utilizar tuberías para STDIO que no eran TTY. Las versiones anteriores utilizaban sockets, que PODRÍAN diferenciarse de dentro de bash utilizando [[ -S ]] .

Cuando importa

Esta limitación normalmente causa problemas cuando se desea escribir una secuencia de comandos bash que tenga un comportamiento similar al de una utilidad compilada, como cat . Por ejemplo, cat permite el siguiente comportamiento flexible en el manejo de varias fuentes de entrada simultáneamente, y es lo suficientemente inteligente como para determinar si está recibiendo una entrada canalizada independientemente de si se está utilizando ssh no TTY o TTY forzado:

ssh -t localhost ''echo piped | cat - <( echo substituted )'' ssh -T localhost ''echo piped | cat - <( echo substituted )''

Solo puede hacer algo así si puede determinar de manera confiable si las tuberías están involucradas o no. De lo contrario, la ejecución de un comando que lee STDIN cuando no hay entrada disponible desde los conductos o la redirección hará que el script se bloquee y espere la entrada de STDIN.

Otras cosas que no funcionan.

Al tratar de resolver este problema, he observado varias técnicas que no logran resolver el problema, incluidas las que involucran:

  • examinando las variables del entorno SSH
  • usando stat en los descriptores de archivo / dev / stdin
  • examinando el modo interactivo a través de [[ "${-}" =~ ''i'' ]]
  • examinando el estado de tty vía tty y tty -s
  • examinando el estado de ssh través de [[ "$(ps -o comm= -p $PPID)" =~ ''sshd'' ]]

Tenga en cuenta que si está utilizando un sistema operativo que admita el sistema de archivos virtual /proc , es posible que tenga suerte al seguir los enlaces simbólicos de STDIO para determinar si se está utilizando una canalización o no. Sin embargo, /proc no es una solución multiplataforma compatible con POSIX.

Estoy extremadamente interesado en resolver este problema, así que avíseme si piensa en alguna otra técnica que pueda funcionar, preferiblemente en soluciones basadas en POSIX que funcionen tanto en Linux como en BSD.


No menciona qué shell está utilizando, pero en Bash, puede hacer esto:

#!/bin/bash if [[ -t 1 ]]; then # stdout is a terminal else # stdout is not a terminal fi