So prüfen Sie, ob eine Shell angemeldet / interaktiv / stapelweise ist

144

Ich denke, ich verstehe die Unterschiede zwischen einer interaktiven, einer Login- und einer Batch-Shell. Weitere Hilfe finden Sie unter den folgenden Links:

Meine Frage ist, wie kann ich mit einem Befehl / einer Bedingung testen, ob ich mich in einer interaktiven, einer Anmelde- oder einer Batch-Shell befinde?

Ich suche nach einem Befehl oder einer Bedingung (die trueoder zurückgibt false) und die ich auch auf eine if-Anweisung setzen könnte. Zum Beispiel:

if [[ condition ]]
   echo "This is a login shell"
fi
Amelio Vazquez-Reina
quelle
3
Es gibt noch eine andere Frage: Sind STDIN und / oder STDOUT mit einem tty (Terminal) oder einer Pipe (Datei oder Prozess) verbunden? Dies ist ein verwandter, aber eindeutiger Test, wie in einigen der folgenden Kommentare beschrieben.
Mark Hudson

Antworten:

161

Ich gehe von einer bashShell oder ähnlichem aus, da in den Tags keine Shell aufgeführt ist.

So überprüfen Sie, ob Sie sich in einer interaktiven Shell befinden:

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

So überprüfen Sie, ob Sie sich in einer Anmeldeshell befinden:

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

Mit "Batch" meine ich "nicht interaktiv", daher sollte die Überprüfung für eine interaktive Shell ausreichen.

Chris Down
quelle
12
Für zshBenutzer kann nach einer Anmeldeshell if [[ -o login ]] ...
gesucht
1
Wenn Sie wissen möchten, ob ein "Benutzer" Ihr Programm im Vergleich zu "cron" ausgeführt hat. [[TERM == "dumm"]] && echo "Laufen in Cron.
Erik Aronesty
10
@ErikAronesty Nicht alle dummen Terminals sind Cron-Sitzungen.
Chris Down
2
„Ich gehe von einer Bash-Shell oder ähnlichem aus, da in den Tags keine Shell aufgeführt ist.“ - Die Logik dieser Aussage ist wirklich wunderschön! :)
Michael Le Barbier Grünewald
2
@antonio Das liegt daran, dass Ihr Zitat falsch $-ist und in der aktuellen Shell erweitert wird. Wenn Sie den vollständigen Ausdruck in einfache Anführungszeichen setzen, erhalten Sie das richtige Ergebnis:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down
33

In jeder Bourne-artigen Shell gibt die iOption an, ob die Shell interaktiv ist:

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

Es gibt keine tragbare und absolut zuverlässige Möglichkeit, eine Login-Shell zu testen. KSH und zsh hinzufügen lzu $-. Bash legt die login_shellOption fest, mit der Sie abfragen können shopt -q login_shell. Testen Sie portabel, ob $0Starts mit a -: Shells normalerweise wissen, dass es sich um Login-Shells handelt, da der Aufrufer dem -Argument Null ein Präfix hinzugefügt hat (normalerweise den Namen oder den Pfad der ausführbaren Datei). Dies kann keine Shell-spezifischen Methoden zum Aufrufen einer Login-Shell erkennen (z ash -l. B. ).

Gilles
quelle
(...) weil der Anrufer - Ich denke, in diesem Fragment fehlt etwas.
Piotr Dobrogost
Es wäre ideal, wenn $0immer mit einer -Sache angefangen würde, egal wie sie angefangen wurde. Es gibt jedoch mindestens eine Ausnahme: Dies gilt nicht immer für Bash, auch wenn es sich um eine Anmeldeshell handeln soll. Versuchen Sie es in Ihrer Box: aufrufen bash --login, dann $0liest noch bash.
Wirawan Purwanto
@WirawanPurwanto Ich bin nicht sicher, ob ich Ihren Kommentar verstehe. Ist es nicht das, was ich in meinem letzten Satz geschrieben habe?
Gilles
@ Gilles: Du hast recht. Entschuldigung, ich habe deinen letzten Satz verpasst.
Wirawan Purwanto
24

Fischmuschel

Hier ist die Antwort für den fishFall, dass andere Benutzer auf diese Seite stoßen.

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"

Fischdokumentation: Initialisierung

Oh, trotz
quelle
1
-1 für unnötige Redaktion.
Nick Bastin
6
Wenn sich jemand über den Kommentar von @ NickBastin wundert, hatte er ein gutes Argument, also habe ich ihn bearbeitet. Die ursprüngliche Menge an Snarkiness wurde nun halbiert.
Trotzdem
18

csh / tcsh

Für cshund tcshich habe folgendes in meiner .cshrcAkte:

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

Speziell für tcshwird die Variable loginshfür eine Login-Shell gesetzt:

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

( tcshHat auch eine Variable, shlvldie auf die Anzahl der verschachtelten Shells festgelegt ist, wobei die Anmeldeshell den Wert 1 hat.)

Andrew Stein
quelle
2
PS1funktioniert nicht zum Testen einer interaktiven Shell. Es ist fast immer in ein interaktives gesetzt, aber Sie können es deaktivieren. Es befindet sich sehr oft in einer nicht interaktiven Shell, da viele Systeme mit export PSin ausgeliefert werden /etc/profile.
Gilles
@ Gilles Danke für die Korrektur und Bearbeitung
Andrew Stein
17

Eine andere Möglichkeit besteht darin, das Ergebnis von zu überprüfen tty

if [ "`tty`" != "not a tty" ]; then
Adrian Cornish
quelle
10
... oder [ -t 0 ]zum Testen, ob STDIN eine tty ist. Sie können je nach Bedarf auch 1 (STDOUT) oder 2 (STDERR) verwenden.
Derobert
@derobert - danke, dass du mir etwas Neues gezeigt hast
Adrian Cornish
10
Dies ist ein anderer Test. Es ist möglich, eine nicht interaktive Shell zu haben, deren Eingabe ein Terminal ist (immer wenn Sie ein Skript in einem Terminal ausführen!), Und es ist möglich (wenn auch selten), dass eine interaktive Shell keine Eingabe von einem Terminal entgegennimmt.
Gilles
@Gilles Wenn die Shell interaktiv und geschlossen war und ein Kind disownam Leben ließ, ttyfunktionierte sie am besten, um zu wissen, dass sie nicht mehr interaktiv ist, obwohl sie $-sich nicht geändert hat. Ich bin immer noch verwirrt, was der beste Ansatz ist.
Aquarius Power
5
@AquariusPower Was Sie dann testen möchten, ist nicht für eine interaktive Shell, sondern ob die Standardeingabe ein Terminal ist. Verwenden Sie [ -t 0 ]. PS In meinem vorherigen Kommentar schrieb ich, dass „es eine starke Korrelation gibt“ - ich vergaß „abgesehen von dem extrem häufigen Fall eines Skripts, das mit #!/bin/shoder ähnlichem begonnen wurde“, das nicht interaktiv ist, aber mit einem Terminal verbunden werden kann.
Gilles
8

UNIX / Linux verfügt über einen Befehl, mit dem Sie überprüfen können, ob Sie sich an einem Terminal befinden.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi
Paul
quelle
1
Das funktioniert dashauch.
Ken Sharp
7

Sie können überprüfen, ob stdin ein Terminal ist:

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

Um zu überprüfen, ob ein Skript in einer interaktiven oder nicht interaktiven Shell ausgeführt wird, überprüfe ich meine Skripte auf das Vorhandensein einer in der $PS1Variablen gespeicherten Eingabeaufforderung :

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

Dies habe ich hier gelernt: https://www.tldp.org/LDP/abs/html/intandnonint.html

Christian Herenz
quelle
1

iist nicht die richtige Option zu suchen. -ibesteht darin, eine ansonsten nicht interaktive Shell zu zwingen, interaktiv zu werden. Die richtige automatisch aktivierte Option ist -s, aber Bash behandelt dies leider nicht richtig.

Sie müssen prüfen, ob $-enthält s(dies wird für die automatische Aktivierung gewährt) oder ob es enthält i(dies wird nicht für die automatische Aktivierung gewährt, sondern ist offiziell nur mit der -iBefehlszeilenoption der Shell gekoppelt ).

schily
quelle
1
sWäre, wenn die Shell Befehle von stdin liest, nicht, ob es interaktiv ist. Eine interaktive Shell liest nicht unbedingt Befehle aus stdin (try zsh -i < /dev/null, obwohl zsh hier die Ausnahme zu sein scheint). Und eine Shell liest möglicherweise Befehle von stdin und ist nicht interaktiv (wie sh < fileoder echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas
2
Was ich darauf hinweisen wollte, ist, dass die ursprüngliche Bourne-Shell kein 'i' in $ - hat, auch wenn sie interaktiv sein soll.
Schily
OK, aber in U & L beziehen sich "Muscheln" in der Regel auf moderne Muscheln. Die Bourne-Shell wird im Allgemeinen als Reliquie betrachtet und Ihre eigene Variante ist nicht mainstream genug, um zu erwarten, dass die Leute wissen, wovon Sie sprechen, es sei denn, Sie machen es explizit. Die erwähnte Frage, [[...]]die ksh / bash / zsh impliziert. Sie haben einen Punkt als bekam Geschichte zur Kenntnis , dass für die Überprüfung iin $-wird in dem Bourne - Shell nicht. Aber dann sfunktioniert das Prüfen auf auch dort nicht zuverlässig. Sie möchten auch nach [ -t 0 ]oder isuchen. Selbst dann würde man sich in Eckfällen wieecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas
Solaris bis Solaris 10 wird mit der Original-Bourne-Shell ausgeliefert, und sogar die Sill-Version enthält ungefähr. 10 Bugs in der Shell seit SVr4. Das Hinzufügen eines Hinweises auf die Bourne-Shell ist also nicht umständlich, wie Sie vielleicht glauben. zsh auf der anderen Seite ist nicht kompatibel genug, es schlägt zB fehl, wenn Sie versuchen, "configure" mit zsh auszuführen. Achten Sie also darauf, / bin / sh so einzurichten, dass es auf zsh zeigt. Übrigens: Meine Bourne-Shell setzt standardmäßig -i, falls sie sich für interaktiv entscheidet.
Schily
3
Ich stelle fest, dass POSIX anscheinend kein $ - include i erfordert (was anscheinend s erfordert). Ich werde die Frage nach der Austin-Group ML stellen.
Stéphane Chazelas