¿Cómo puede un script Bash decir cómo se ejecutó?

10

Tengo un script de Bash que intentaba hacer para ayudarme a ejecutar un comando bastante complejo con pequeños cambios que me preguntaría a través de echo y read.

He encontrado soluciones para forzarlo a ejecutar un terminal para ejecutar el comando, pero no estoy interesado en eso. Lo que me gustaría que hiciera es que, si dejo espacio y presiono Enter en Nautilus (haciendo que se ejecute con Run Software), aparecerá una notificación que dice "Por favor, ejecute esto desde un terminal".

Puedo hacer que aparezca la ventana emergente, ya que conozco el comando, pero no puedo hacer que el script Bash diga si se está ejecutando dentro de una terminal o no, parece que siempre lo creo. ¿Es posible?

Escula
fuente

Respuestas:

10

De man bashbajo expresiones condicionales :

-t fd  
    True if file descriptor fd is open and refers to a terminal.

Asumiendo que fd 1 es estándar, if [ -t 1 ]; thendebería funcionar para usted. La Guía avanzada de secuencias de comandos de Shell afirma que si se -tusa de esta manera fallará sshy que la prueba (usando stdin, no stdout) debería ser:

if [[ -t 0 || -p /dev/stdin ]]

-pprueba si existe un archivo y es una tubería con nombre. Sin embargo , me gustaría tener en cuenta que esto no es cierto para mí: -p /dev/stdinfalla tanto para terminales normales como para sesiones ssh, mientras que if [ -t 0 ](o -t 1) funciona en ambos casos (vea también los comentarios de Gilles a continuación sobre los problemas en esa sección de la Guía avanzada de secuencias de comandos de Shell ).


Si el problema principal es un contexto especializado desde el que desea llamar a la secuencia de comandos para que se comporte de manera apropiada a ese contexto, puede eludir todos estos tecnicismos y ahorrarse un poco de problema utilizando un contenedor y una variable personalizada:

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

Llame a esto live_script.sho lo que sea y haga doble clic en ese lugar. Por supuesto, podría lograr lo mismo con los argumentos de la línea de comandos, pero aún se necesitaría un contenedor para hacer que señalar y hacer clic en un navegador de archivos GUI funcione.

encerrada dorada
fuente
55
esta es la respuesta correcta: también es cómo POSIX dice que un shell debería detectar si es interactivo o no.
mikeserv
2
@DanielAmaya: si redirige la entrada, el script no se ejecuta en una terminal. La pregunta es cómo detectar si el script se está ejecutando en un terminal.
mikeserv
2
¿Estás seguro sobre el uso de ||dentro de [ … ]esa manera? Si lo usa [[ … ]], estaría bien, pero normalmente ||se usa para separar comandos y [ -t 0es una invocación incorrecta de [porque ]falta el último . Por lo general, tampoco hay un comando -p. Estoy de acuerdo con las pruebas para un terminal; esa es probablemente la forma de hacerlo. Es solo la sintaxis lo que me preocupa.
Jonathan Leffler
1
@JonathanLeffler Derecha; eso debería producir un error de sintaxis, ya que el operador de shell ||se ve antes del ]argumento final requerido para [.
chepner
3
Esa sección de la Guía avanzada de secuencias de comandos Bash tiene varios errores. PS1No es una prueba confiable para saber si el shell es interactivo. "Si un script necesita probar si se está ejecutando en un shell interactivo" también es confuso: debería ser si algún código necesita probar, un script generalmente no se está ejecutando en un shell interactivo (pero puede serlo, si se obtiene) . La prueba de iin $-es la forma correcta de probar si el shell es interactivo. Probar -t 0o -t 2es la forma correcta de saber si el script se está ejecutando en una terminal, lo que es diferente de ser interactivo.
Gilles 'SO- deja de ser malvado'
0

Use la variable bash $ SHLVL para detectar el nivel de anidación de shell. En una secuencia de comandos ejecutada 'raw' haciendo doble clic, será 1, en una secuencia de comandos que se ejecuta dentro de un terminal será 2.

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script
Ed Randall
fuente
0

Aunque la respuesta de Ricitos de Oro es probablemente correcta en el caso típico, parece que hay casos extremos. En mi propio caso, mi servidor x está configurado para iniciarse tty1y nunca sale de ese tty. Si Xorg's stdoutes un TTY, entonces parece que los clientes tendrán ese TTY vinculado a su descriptor de archivo de forma predeterminada.

Así es como resolví mi problema:

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

No he probado esto para ver si funciona en una configuración X más estándar, y también dudo mucho de que este sea el único caso límite. Si alguien encuentra una solución más generalmente aplicable, regrese y díganos.

JMW
fuente
-2

Otra, mediante las opciones de bash establecidos variable interna, $-.

De .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac
xae
fuente
un shell interactivo no está necesariamente conectado a un terminal. mientras que uno iniciado con esa conexión se inicia automáticamente interactiva, esto también es posible: cmd | sh -i | cmd.
mikeserv
Este código se está ejecutando en un script. No será interactivo, incluso si se está ejecutando en una terminal.
Gilles 'SO- deja de ser malvado'