¿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 forma interactiva, pero no cuando se canaliza, de forma similar a lo que ls --colorhace.

Respuestas:
En un shell POSIX puro,
devuelve "terminal", porque la salida se envía a su terminal, mientras que
devuelve "no un terminal", porque la salida del paréntesis se canaliza a
cat.La
-tbandera se describe en las páginas del manual como... donde
fdpuede ser una de las asignaciones de descriptor de archivo habituales:fuente
-tindicador se especifica en POSIX y, por lo tanto, debería funcionar para cualquier shell compatible con POSIX (es decir, no es una extensión bash). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfishrespuesta de shell. El usotestes ordenado, pero no puedo probar el ejemplo entre paréntesis, ya que no es compatible. Intenté envolverlo de manera análogabegin; ...; end, pero eso no pareció funcionar, y simplemente ejecutó el bloque de código positivo nuevamente. Pensé que podría necesitar usar,statuspero eso no parece comprobar si hay tuberías. Supongo que esencialmente quiero comprobar si STDOUT de un comando / script anterior no está configurado en el terminal, gracias a estas aclaraciones.No hay una forma infalible de determinar si STDIN, STDOUT o STDERR se están canalizando hacia / desde su script, principalmente debido a programas como
ssh.Cosas que "normalmente" funcionan
Por ejemplo, la siguiente solución bash funciona correctamente en un shell interactivo:
Pero no siempre funcionan
Sin embargo, al ejecutar este comando como un comando que no es TTY
ssh, las transmisiones STD siempre parecen estar siendo canalizadas. Para demostrar esto, use STDIN porque es más fácil:Por que es importante
Este es un gran problema, porque implica que no hay forma de que un script bash sepa si un
sshcomando que no es tty se está canalizando o no. Tenga en cuenta que este comportamiento desafortunado se introdujo cuando las versiones recientes desshcomenzaron a utilizar tuberías para STDIO no TTY. Las versiones anteriores usaban sockets, que PODRÍAN diferenciarse desde dentro de bash usando[[ -S ]].Cuando importa
Esta limitación normalmente causa problemas cuando desea escribir un script bash que tenga un comportamiento similar a una utilidad compilada, como
cat. Por ejemplo,catpermite 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 sisshse está utilizando TTY no forzado o TTY forzado :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 cualquiera de las tuberías o la redirección dará como resultado que el script se cuelgue y espere la entrada de STDIN.
Otras cosas que no funcionan
Al tratar de resolver este problema, he examinado varias técnicas que no logran resolverlo, incluidas las que incluyen:
statdescriptores de archivo on / dev / stdin[[ "${-}" =~ 'i' ]]ttyytty -ssshestado a través de[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]Tenga en cuenta que si está utilizando un sistema operativo que admite el
/procsistema de archivos virtual, es posible que tenga suerte siguiendo los enlaces simbólicos de STDIO para determinar si se está utilizando una tubería o no. Sin embargo,/procno es una solución multiplataforma compatible con POSIX.Soy extremadamente interesante para resolver este problema, así que avíseme si piensa en alguna otra técnica que pueda funcionar, preferiblemente soluciones basadas en POSIX que funcionen tanto en Linux como en BSD.
fuente
statllamada en / dev / stdin. ¿Y por qué funciona"${-}"otty -sno? También busqué en el código fuente decatpero no veo qué parte está haciendo la magia allí que no puedes hacer en el shell POSIX. ¿Puede explicar más?El comando
test(incorporadobash) tiene una opción para verificar si un descriptor de archivo es un tty.Ver "
man test" o "man bash" y buscar "-t"fuente
help test(yhelp helppara más), luegoinfo bashpara obtener información más detallada. Estos comandos son excelentes si alguna vez terminas haciendo scripts fuera de línea, o si solo quieres obtener una comprensión más amplia.No mencionas qué shell estás usando, pero en Bash, puedes hacer esto:
fuente
En Solaris, la sugerencia de Dejay Clayton funciona principalmente. La -p no responde como se desea.
bash_redir_test.sh se parece a:
En Linux, funciona muy bien:
En Solaris:
fuente
El siguiente código (probado solo en linux bash 4.4) no debe considerarse portátil ni recomendado , pero en aras de la exhaustividad aquí es:
No sé por qué, pero parece que el descriptor de archivo "3" se crea de alguna manera cuando una función bash tiene STDIN canalizado.
Espero eso ayude,
fuente