Come verificare se una shell è login / interattivo / batch


145

Penso di comprendere le differenze tra una shell interattiva, un login e una batch. Vedere i seguenti collegamenti per ulteriori informazioni:

La mia domanda è: come posso testare con un comando / condizione se mi trovo su una shell interattiva, di accesso o batch?

Sto cercando un comando o una condizione (che ritorna trueo false) e che potrei anche inserire in un'istruzione if. Per esempio:

if [[ condition ]]
   echo "This is a login shell"
fi

3
C'è ancora un'altra domanda: STDIN e / o STDOUT sono collegati a un tty (terminale) o una pipe (file o processo)? Questo è un test correlato ma distinto, come descritto in alcuni dei commenti seguenti.
Mark Hudson,

Risposte:


162

Sto assumendo una bashshell, o simile, dal momento che non c'è nessuna shell elencata nei tag.

Per verificare se ci si trova in una shell interattiva:

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

Per verificare se ci si trova in una shell di accesso:

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

Per "batch", suppongo che intendi "non interattivo", quindi il controllo per una shell interattiva dovrebbe essere sufficiente.


12
Per gli zshutenti, è possibile verificare la presenza di una shell di accesso con:if [[ -o login ]] ...
chb,

1
Se vuoi sapere se un "utente" ha eseguito il tuo programma contro "cron". [[TERM == "dumb"]] && echo "In esecuzione in cron.
Erik Aronesty,

10
@ErikAronesty Non tutti i terminali stupidi sono sessioni cron.
Chris Down,

2
"Sto assumendo una shell bash, o simile, dal momento che non esiste alcuna shell elencata nei tag." - La logica di questa affermazione è davvero meravigliosa! :)
Michael Le Barbier Grünewald,

2
@antonio Questo perché il tuo preventivo è sbagliato, $-viene espanso nella shell corrente. Se usi le virgolette singole intorno all'espressione completa otterrai il risultato corretto:bash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
Chris Down

33

In qualsiasi shell in stile Bourne, l' iopzione indica se la shell è interattiva:

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

Non esiste un modo portatile e completamente affidabile per testare una shell di accesso. Ksh e zsh si aggiungono la $-. Bash imposta l' login_shellopzione, con cui è possibile eseguire una query shopt -q login_shell. Portabilmente, verifica se $0inizia con a -: le shell normalmente sanno di essere shell di login perché il chiamante ha aggiunto un -prefisso all'argomento zero (normalmente il nome o il percorso dell'eseguibile). Questo non riesce a rilevare modi specifici della shell di invocare una shell di login (ad es ash -l.).


(...) perché il chiamante - penso che manchi qualcosa in questo frammento.
Piotr Dobrogost,

Sarebbe l'ideale se $0inizia sempre con -non importa come è stato avviato. Ma c'è almeno un'eccezione: questo non è sempre vero con bash anche se si suppone che sia una shell di login. Provalo nella tua scatola: invoca bash --login, poi $0legge ancora bash.
Wirawan Purwanto,

@WirawanPurwanto Non sono sicuro di aver capito il tuo commento. Non è quello che ho scritto nella mia ultima frase?
Gilles,

@Gilles: hai ragione. Scusa, ho perso la tua ultima frase.
Wirawan Purwanto,

24

conchiglia di pesce

Ecco la risposta fishnel caso in cui altri utenti si imbattessero in questa pagina.

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"

Documentazione sui pesci: inizializzazione


1
-1 per editoria non necessaria.
Nick Bastin,

6
Se qualcuno si domanda al commento di @ NickBastin, ha avuto un buon punto, quindi ho fatto una modifica. La quantità originale di snarkiness è stata ora dimezzata.
oh

18

csh / tcsh

Per cshe tcshho il seguente nel mio .cshrcfile:

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

In particolare per tcsh, la variabile loginshè impostata per una shell di login:

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

( tcshha anche una variabile shlvlche è impostata sul numero di shell nidificate, dove la shell di login ha un valore di 1.)


2
PS1non funziona per testare una shell interattiva. È quasi sempre impostato in modo interattivo, ma è possibile annullarlo. Molto spesso è impostato in una shell non interattiva, perché molti sistemi vengono forniti con export PSin /etc/profile.
Gilles,

@Gilles Grazie per la correzione e la modifica
Andrew Stein,

17

Un altro modo è verificare il risultato di tty

if [ "`tty`" != "not a tty" ]; then

10
... oppure usa [ -t 0 ]per verificare se STDIN è un valore. Puoi anche usare 1 (STDOUT) o 2 (STDERR) in base alle tue esigenze.
derobert,

@derobert - grazie per avermi mostrato qualcosa di nuovo
Adrian Cornish,

10
Questo è un test diverso. È possibile avere una shell non interattiva il cui input è un terminale (ogni volta che si esegue uno script in un terminale!), Ed è possibile (anche se raro) avere una shell interattiva che prende input non da un terminale.
Gilles,

@Gilles se la shell era interattiva e chiusa lasciando un bambino disownvivo, ttyfunzionava meglio per sapere che non era più interattiva, mentre $-non cambiava; Sono ancora perplesso su quale sia l'approccio migliore.
Aquarius Power il

5
@AquariusPower Quindi quello che vuoi testare non è per una shell interattiva, ma se l'input standard è un terminale. Usa [ -t 0 ]. PS Nel mio precedente commento, ho scritto che "esiste una forte correlazione" - ho dimenticato "a parte il caso estremamente comune di uno script iniziato con #!/bin/sho simili", che non è interattivo ma può essere collegato a un terminale.
Gilles,

8

UNIX / Linux ha un comando per verificare se ci si trova su un terminale.

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
Questo funziona dashanche in.
Ken Sharp,

7

Puoi verificare se stdin è un terminale:

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

3

Per verificare se uno script viene eseguito in una shell interattiva o non interattiva, controllo nei miei script la presenza di un prompt memorizzato nella $PS1variabile:

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

Questo l'ho imparato qui: https://www.tldp.org/LDP/abs/html/intandnonint.html


1

inon è l'opzione corretta da cercare. -iè forzare una shell altrimenti non interattiva a diventare interattiva. L'opzione auto-abilitata corretta è -s, ma purtroppo Bash non la gestisce correttamente.

È necessario verificare se $-contiene s(questo è concesso per essere attivato automaticamente) o se contiene i(questo non è concesso per essere attivato automaticamente ma ufficialmente accoppiato solo con l' -iopzione della riga di comando della shell).


1
ssarebbe se la shell legge i comandi da stdin, non se è interattiva. Una shell interattiva non legge necessariamente i comandi di stdin (prova zsh -i < /dev/null, anche se qui zsh sembra essere l'eccezione). E una shell può leggere comandi da stdin e non essere interattiva (come sh < fileo echo 'echo "$1"' | sh -s foo bar).
Stéphane Chazelas,

2
Quello che volevo sottolineare è che l'originale Bourne Shell non ha "i" in $, anche quando è inteso essere interattivo.
schily,

OK, ma su U&L, "shell" tende a riferirsi a shell moderne . La shell Bourne è generalmente considerata un relitto e la tua variante non è abbastanza mainstream da aspettarti che le persone sappiano di cosa stai parlando a meno che non lo rendi esplicito. La domanda menzionata [[...]]che implica ksh / bash / zsh. Hai un punto come nota storica che il check- iin $-non funzionerà nella shell Bourne. Ma poi anche il controllo per snon funzionerà in modo affidabile. Vorresti anche controllare per [ -t 0 ]o i; anche allora sarebbe stato ingannato in casi d'angolo comeecho 'exec < /dev/tty; that-check' | sh'
Stéphane Chazelas il

Solaris fino a Solaris 10 viene fornito con l'originale Bourne Shell e anche il davanzale include aprox. 10 bug noti per essere nella shell da SVr4. Quindi aggiungere un suggerimento su Bourne Shell non è un cappello subdolo come si potrebbe credere. zsh dall'altro lato non è sufficientemente compatibile, ad esempio non riesce quando si tenta di eseguire "configura" con zsh, quindi attenzione a impostare / bin / sh per puntare a zsh. A proposito: la mia Bourne Shell imposta -i di default nel caso in cui decida di essere interattivo.
schily,

3
Ho notato che POSIX non sembra richiedere $ - contiene i (che sembra richiedere s), solleverò la domanda sull'ML del gruppo austin.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.