Comment vérifier si un shell est connecté / interactif / batch

145

Je pense comprendre les différences entre un shell interactif, un login et un batch. Voir les liens suivants pour plus d'aide:

Ma question est, comment puis-je tester avec une commande / condition si je suis sur un shell interactif, un login ou batch?

Je cherche une commande ou une condition (qui renvoie trueou false) et que je pourrais également placer sur une instruction if. Par exemple:

if [[ condition ]]
   echo "This is a login shell"
fi
Amelio Vazquez-Reina
la source
3
Il y a encore une autre question: STDIN et / ou STDOUT sont-ils connectés à un tty (terminal) ou à un canal (fichier ou processus)? Il s'agit d'un test lié, mais distinct, décrit dans certains des commentaires ci-dessous.
Mark Hudson

Réponses:

162

Je suppose un bashshell, ou similaire, car il n'y a pas de shell dans les balises.

Pour vérifier si vous êtes dans un shell interactif:

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

Pour vérifier si vous êtes dans un shell de connexion:

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

Par "batch", je suppose que vous voulez dire "non interactif", le contrôle d'un shell interactif devrait donc suffire.

Chris Down
la source
12
Pour les zshutilisateurs, il est possible de rechercher un shell de connexion avec:if [[ -o login ]] ...
chb
1
Si vous voulez savoir si un "utilisateur" a exécuté votre programme par opposition à "cron". [[TERM == "dumb"]] && echo "Courir dans le cron.
Erik Aronesty
10
@ErikAronesty Tous les terminaux muets ne sont pas des sessions cron.
Chris Down
2
"Je suppose un shell bash ou similaire, car aucun tag n'est répertorié dans les tags." - La logique de cette affirmation est vraiment magnifique! :)
Michael Le Barbier Grünewald
2
@antonio C'est parce que votre citation est fausse, elle $-est développée dans le shell actuel. Si vous utilisez des guillemets simples autour de l'expression complète, vous obtiendrez le résultat correct:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down
33

Dans n'importe quel shell de style Bourne, l' ioption indique si le shell est interactif:

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

Il n'y a pas de moyen portable et totalement fiable de tester un shell de connexion. Ksh et zsh ajoutent là $-. Bash définit l' login_shelloption avec laquelle vous pouvez interroger shopt -q login_shell. De manière portable, vérifiez si $0commence par un -: shells savent normalement qu'ils sont des shells de connexion, car l'appelant a ajouté un -préfixe à l'argument zéro (normalement le nom ou le chemin de l'exécutable). Cela ne permet pas de détecter les moyens d’appeler un shell de connexion spécifiques à un shell (par exemple ash -l).

Gilles
la source
(...) parce que l'appelant - Je pense qu'il manque quelque chose dans ce fragment.
Piotr Dobrogost
Ce serait idéal si $0on commençait toujours par un -peu importe comment on avait commencé. Mais il y a au moins une exception: ce n'est pas toujours vrai avec bash même s'il est supposé être un shell de connexion. Essayez-le dans votre boîte: invoke bash --login, puis $0lit toujours bash.
Wirawan Purwanto
@WirawanPurwanto Je ne suis pas sûr de comprendre votre commentaire. N'est-ce pas ce que j'ai écrit dans ma dernière phrase?
Gilles
@ Gilles: Vous avez raison. Désolé, j'ai raté votre dernière phrase.
Wirawan Purwanto
24

coquille de poisson

Voici la réponse fishau cas où d'autres utilisateurs tomberaient sur cette page.

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"

Documentation poisson: initialisation

oh mais
la source
1
-1 pour une éditorialisation inutile.
Nick Bastin
6
Si quelqu'un s'interroge sur le commentaire de @ NickBastin, il avait raison, alors j'ai fait un montage. La quantité initiale de snarkiness a maintenant été réduite de moitié.
ohspite
18

csh / tcsh

Pour cshet tcshj'ai dans mon .cshrcdossier:

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

Spécifiquement pour tcsh, la variable loginshest définie pour un shell de connexion:

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

(a tcshégalement une variable shlvlqui est définie sur le nombre de shells imbriqués, où le shell de connexion a une valeur de 1.)

Andrew Stein
la source
2
PS1ne fonctionne pas pour tester un shell interactif. Il est presque toujours défini comme interactif, mais vous pouvez le désactiver. Il est très souvent situé dans une coquille noninteractive, parce que de nombreux systèmes navire avec export PSen /etc/profile.
Gilles
@ Gilles Merci pour la correction et la modification
Andrew Stein
17

Une autre façon est de vérifier le résultat de tty

if [ "`tty`" != "not a tty" ]; then
Adrian Cornish
la source
10
... ou utiliser [ -t 0 ]pour tester si STDIN est un tty. Vous pouvez également utiliser 1 (STDOUT) ou 2 (STDERR) selon vos besoins.
derobert
@derobert - merci de me montrer quelque chose de nouveau
Adrian Cornish
10
Ceci est un test différent. Il est possible d'avoir un shell non interactif dont l'entrée est un terminal (à chaque fois que vous exécutez un script dans un terminal!), Et il est possible (bien que rare) de disposer d'un shell interactif ne prenant aucune entrée d'un terminal.
Gilles
@Gilles si le shell était interactif et fermé, laissant un enfant en disownvie, ttytravaillait mieux pour savoir qu'il n'était plus interactif, alors $-qu'il ne changeait pas; Je suis toujours perplexe quant à la meilleure approche.
Aquarius Power
5
@AquariusPower Alors ce que vous voulez tester n'est pas pour un shell interactif, mais si l'entrée standard est un terminal. Utilisez [ -t 0 ]. PS Dans mon précédent commentaire, j’écrivais qu’il existait «une forte corrélation», j’avais oublié «à part le cas extrêmement courant d’un script démarré avec #!/bin/shou similaire», qui est non interactif mais peut être connecté à un terminal.
Gilles
8

UNIX / Linux a une commande pour vérifier si vous êtes sur un terminal.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi
Paul
la source
1
Cela fonctionne dashaussi.
Ken Sharp
7

Vous pouvez vérifier si stdin est un terminal:

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

Pour vérifier si un script s'exécute dans un shell interactif ou non interactif, je vérifie dans mes scripts la présence d'une invite stockée dans la $PS1variable:

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

J'ai appris cela ici: https://www.tldp.org/LDP/abs/html/intandnonint.html

Christian Herenz
la source
1

in'est pas la bonne option à rechercher. -iconsiste à forcer un shell non interactif à devenir interactif. L'option d'activation automatique correcte est -s, mais Bash ne le gère malheureusement pas correctement.

Vous devez vérifier si $-contient s(ceci est autorisé à être activé automatiquement) ou s'il contient i(ceci n'est pas autorisé à être activé automatiquement, mais uniquement couplé à l' -ioption de ligne de commande du shell).

schily
la source
1
sserait si le shell lit les commandes de stdin, pas si c'est interactif. Un shell interactif ne lit pas nécessairement les commandes de stdin (essayez zsh -i < /dev/null, bien que zsh semble être l'exception ici). Et un shell peut lire des commandes à partir de stdin et ne pas être interactif (comme sh < fileou echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas
2
Ce que je voulais souligner, c'est que le Bourne Shell d'origine n'a pas de «i» dans $ -, même s'il est censé être interactif.
Schily
OK, mais sur U & L, "coquille" a tendance à faire référence aux coquilles modernes . Le shell Bourne est généralement considéré comme une relique et votre propre variante n’est pas assez répandue pour que les gens sachent de quoi vous parlez, à moins que vous ne le rendiez explicite. La question mentionnée [[...]]qui implique ksh / bash / zsh. Vous avez un point en tant que note d’historique, à savoir que la vérification de idans $-ne fonctionnera pas dans le shell Bourne. Mais alors vérifier sne fonctionnera pas là non plus de manière fiable. Vous voudriez aussi vérifier [ -t 0 ]ou i; même dans ce cas, on serait dupe dans des dossiers commeecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas
Les versions Solaris à Solaris 10 sont livrées avec le Bourne Shell d’origine et incluent même un seuil. 10 bugs connus pour être dans le shell depuis SVr4. Donc, ajouter un indice sur le Bourne Shell n’est pas un casse-tête, comme vous pourriez le croire. zsh de l’autre côté n’est pas suffisamment compatible, il échoue par exemple lorsque vous essayez d’exécuter "configure" avec zsh, alors prenez garde de configurer / bin / sh pour qu’il pointe vers zsh. BTW: mon Bourne Shell définit -i par défaut au cas où il déciderait d'être interactif.
Schily
3
Je remarque que POSIX ne semble pas nécessiter de $ - contenir i (ce qui semble être nécessaire), je soulèverai la question sur le groupe austin du groupe.
Stéphane Chazelas