Cómo verificar si un shell es de inicio de sesión / interactivo / por lotes

145

Creo que entiendo las diferencias entre un shell interactivo, un inicio de sesión y un lote. Consulte los siguientes enlaces para obtener más ayuda:

Mi pregunta es, ¿cómo puedo probar con un comando / condición si estoy en un shell interactivo, de inicio de sesión o por lotes?

Estoy buscando un comando o condición (que devuelve trueo false) y que también podría colocar en una declaración if. Por ejemplo:

if [[ condition ]]
   echo "This is a login shell"
fi
Amelio Vazquez-Reina
fuente
3
Todavía hay otra pregunta: ¿STDIN y / o STDOUT están conectados a un tty (terminal) o una tubería (archivo o proceso)? Esta es una prueba relacionada pero distinta como se describe en algunos de los comentarios a continuación.
Mark Hudson

Respuestas:

162

Asumo un bashshell, o similar, ya que no hay un shell en las etiquetas.

Para verificar si está en un shell interactivo:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

Para verificar si está en un shell de inicio de sesión:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

Por "lote", supongo que quiere decir "no interactivo", por lo que la comprobación de un shell interactivo debería ser suficiente.

Chris Down
fuente
12
Para los zshusuarios, la comprobación de un shell de inicio de sesión se puede hacer con:if [[ -o login ]] ...
chb
1
Si desea saber si un "usuario" ejecutó su programa versus "cron". [[TERM == "tonto"]] && echo "Ejecutando en cron.
Erik Aronesty
10
@ErikAronesty No todas las terminales tontas son sesiones cron.
Chris Down
2
"Asumo un shell bash, o similar, ya que no hay ningún shell en las etiquetas". ¡La lógica de esta declaración es realmente hermosa! :)
Michael Le Barbier Grünewald
2
@antonio Eso es porque su cita es incorrecta, $-se está expandiendo en el shell actual. Si usa comillas simples alrededor de la expresión completa obtendrá el resultado correcto:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down
33

En cualquier shell de estilo Bourne, la iopción indica si el shell es interactivo:

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

No hay una forma portátil y totalmente confiable de probar un shell de inicio de sesión. Ksh y zsh se suman la $-. Bash establece la login_shellopción, con la que puede consultar shopt -q login_shell. Portablemente, pruebe si $0comienza con a -: los shells normalmente saben que son shells de inicio de sesión porque la persona que llama agregó un -prefijo al argumento cero (normalmente el nombre o la ruta del ejecutable). Esto no puede detectar formas específicas de shell de invocar un shell de inicio de sesión (por ejemplo ash -l).

Gilles
fuente
(...) porque la persona que llama , creo que falta algo en este fragmento.
Piotr Dobrogost
Sería ideal si $0siempre comienza con un -no importa cómo se inició. Pero hay al menos una excepción: esto no siempre es cierto con bash, incluso si se supone que es un shell de inicio de sesión. Pruébelo en su caja: invocar bash --login, luego $0sigue leyendo bash.
Wirawan Purwanto
@WirawanPurwanto No estoy seguro de entender tu comentario. ¿No es eso lo que escribí en mi última oración?
Gilles
@Gilles: Tienes razón. Lo siento, me perdí tu última oración.
Wirawan Purwanto
24

concha de pescado

Aquí está la respuesta fishen caso de que otros usuarios se encuentren con esta página.

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Documentación de pescado: inicialización

ohspite
fuente
1
-1 por editorialización innecesaria.
Nick Bastin
66
Si alguien se pregunta por el comentario de @ NickBastin, tenía un punto justo, así que hice una edición. La cantidad original de sarcasmo ahora se ha reducido a la mitad.
ohspite
18

csh / tcsh

Para cshy tcshtengo lo siguiente en mi .cshrcarchivo:

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

Específicamente para tcsh, la variable loginshse establece para un shell de inicio de sesión:

if($?loginsh) then              # A login shell..
    ...
endif

( tcshtambién tiene una variable shlvlque se establece en el número de shells anidados, donde el shell de inicio de sesión tiene un valor de 1.)

Andrew Stein
fuente
2
PS1no funciona para probar un shell interactivo. Casi siempre se configura de forma interactiva, pero puede desactivarlo. Es muy a menudo situado en una cáscara no interactivo, ya que muchos sistemas de la nave con export PSen /etc/profile.
Gilles
@Gilles Gracias por la corrección y edición
Andrew Stein
17

Otra forma es verificar el resultado de tty

if [ "`tty`" != "not a tty" ]; then
Adrian Cornish
fuente
10
... o use [ -t 0 ]para probar si STDIN es un tty. También puede usar 1 (STDOUT) o 2 (STDERR) según sus necesidades.
derobert
@derobert - gracias por mostrarme algo nuevo
Adrian Cornish
10
Esta es una prueba diferente. Es posible tener un shell no interactivo cuya entrada es un terminal (¡cada vez que ejecuta un script en un terminal!), Y es posible (aunque raro) tener un shell interactivo que tome datos no desde un terminal.
Gilles
@Gilles si el caparazón era interactivo y se cerraba dejando a un niño disownvivo, ttyfuncionó mejor para saber que ya no es interactivo, mientras $-que no cambió; Todavía estoy desconcertado sobre cuál es el mejor enfoque.
Acuario Power
55
@AquariusPower Entonces, lo que desea probar no es para un shell interactivo, sino si la entrada estándar es un terminal. Utilizar [ -t 0 ]. PD: En mi comentario anterior, escribí que "hay una fuerte correlación": se me olvidó "aparte del caso extremadamente común de un script iniciado con #!/bin/sho similar", que no es interactivo pero se puede conectar a un terminal.
Gilles
8

UNIX / Linux tiene un comando para verificar si está en una terminal.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi
Pablo
fuente
1
Esto funciona dashtambién en .
Ken Sharp
7

Puede verificar si stdin es una terminal:

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi
Angelo
fuente
3

Para verificar si un script se ejecuta en un shell interactivo o no interactivo, verifico en mis scripts la presencia de un indicador almacenado en la $PS1variable:

if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ]   # On Bash 4.2+ ...
then
  # non-interactive
  ...
else
  # interactive
  ...
fi

Esto lo aprendí aquí: https://www.tldp.org/LDP/abs/html/intandnonint.html

Christian Herenz
fuente
1

iNo es la opción correcta a buscar. -ies forzar un shell que de otro modo no sería interactivo a ser interactivo. La opción correcta habilitada automáticamente es -s, pero Bash desafortunadamente no maneja esto correctamente.

Debe verificar si $-contiene s(se garantiza que se activará automáticamente) o si contiene i(no se garantiza que se active automáticamente, sino que oficialmente solo se acopla a la -iopción de línea de comandos del shell).

astuto
fuente
1
ssería si el shell lee comandos de stdin, no si es interactivo. Un shell interactivo no necesariamente lee los comandos de stdin (intente zsh -i < /dev/null, aunque zsh parece ser la excepción aquí). Y un shell puede estar leyendo comandos de stdin y no ser interactivo (como sh < fileo echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas
2
Lo que quería señalar es que el Bourne Shell original no tiene 'i' en $, incluso cuando está destinado a ser interactivo.
schily
OK, pero en U&L, "shell" tiende a referirse a los shells modernos . El shell Bourne generalmente se considera una reliquia y su propia variante no es lo suficientemente convencional como para esperar que las personas sepan de qué está hablando a menos que lo explique. La pregunta mencionada [[...]]que implica ksh / bash / zsh. Tienes un punto como una nota de la historia que la comprobación de ien $-no funcionará en el shell Bourne. Pero entonces verificar stampoco funcionará allí de manera confiable. También querrá verificar [ -t 0 ]o i; incluso entonces eso sería engañado en casos de esquina comoecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas
Solaris hasta Solaris 10 vienen con el Bourne Shell original e incluso el alféizar incluye aprox. Se sabe que hay 10 errores en el shell desde SVr4. Por lo tanto, agregar una pista sobre el Bourne Shell no es tan engañoso como podría creerse. zsh en el otro lado no es lo suficientemente compatible, por ejemplo, falla cuando intenta ejecutar "configure" con zsh, así que tenga cuidado de configurar / bin / sh para apuntar a zsh. Por cierto: mi Bourne Shell establece -i por defecto en caso de que decida ser interactivo.
schily
3
Noté que POSIX no parece requerir $ - contiene i (que parece requerir s), plantearé la pregunta sobre el ML del grupo Austin.
Stéphane Chazelas