Risposte:
Questo sta verificando se la shell è interattiva o meno. In questo caso, approvvigionare il ~/.bash_profile
file solo se la shell è interattiva.
Vedi "Questa Shell è interattiva?" nel manuale di bash, che cita quel linguaggio specifico. (Si consiglia inoltre di verificare se la shell è interattiva verificando se la $-
variabile speciale contiene il i
carattere, che rappresenta un approccio migliore a questo problema.)
bash
disattiva PS1 quando non interattivo (errore di battitura nel tuo commento precedente) è un bug IMO, PS1 non è una variabile specifica per bash, non ha business che la disattivi. È l'unica shell che lo fa ( yash
anche se imposta anche PS1
un valore predefinito anche quando non interattivo).
[[ $- = *i* ]] && source ~/.bash_profile
).
[ -n "${PS1}" ]
, ma ho ancora aggiornato la mia risposta per evidenziare che il manuale di bash suggerisce anche / raccomanda di ispezionare $-
per determinare se la shell è interattiva, spero che tu trovi che migliora la risposta. Saluti!
Questo è un modo diffuso per verificare se la shell è interattiva. Attenzione che funziona solo in bash, non funziona con altre shell. Quindi va bene (se sciocco) per .bashrc
, ma non funzionerebbe .profile
(che viene letto da sh, e bash è solo una delle possibili implementazioni di sh, e non la più comune).
Una shell interattiva imposta la variabile di shellPS1
sulla stringa di prompt predefinita. Quindi, se la shell è interattiva, PS1
è impostata (a meno che l'utente non l' .bashrc
abbia rimossa, cosa che non può essere ancora avvenuta nella parte superiore di .bashrc
, e si potrebbe considerare che è una cosa sciocca fare comunque).
Il contrario è vero in bash: istanze non interattive di bash disinserite PS1
quando iniziano. Nota che questo comportamento è specifico per bash ed è probabilmente un bug (perché bash -c '… do stuff with $var…'
non dovrebbe funzionare quando lo var
è PS1
?). Ma tutte le versioni di bash fino alla 4.4 inclusa (l'ultima versione mentre scrivo) lo fanno.
Molti sistemi vengono esportati PS1
nell'ambiente. È una cattiva idea, perché molte shell diverse usano PS1
ma con una sintassi diversa (ad esempio , i prompt escape di bash sono completamente diversi dai prompt escape di zsh ). Ma è abbastanza diffuso che in pratica, vedere che PS1
è impostato non è un indicatore affidabile che la shell sia interattiva. La shell potrebbe aver ereditato PS1
dall'ambiente.
.bashrc
è il file che bash legge all'avvio quando è interattivo. Un fatto meno noto è che bash legge anche .bashrc
una shell di login e l'euristica di bash conclude che si tratta di una sessione remota (bash verifica se il suo genitore è rshd
o sshd
). In questo secondo caso, è improbabile che PS1
venga impostato nell'ambiente, poiché non è ancora stato eseguito alcun file dot.
Tuttavia, il modo in cui il codice utilizza queste informazioni è controproducente.
.bash_profile
in quella shell. Ma .bash_profile
è uno script al momento del login. Potrebbe eseguire alcuni programmi che devono essere eseguiti una sola volta per sessione. Potrebbe sovrascrivere alcune variabili di ambiente che l'utente aveva deliberatamente impostato su un valore diverso prima di eseguire quella shell. L'esecuzione .bash_profile
in una shell non di accesso è dirompente..bash_profile
. Ma questo è il caso in cui il caricamento .bash_profile
potrebbe essere utile, perché una shell di login non interattiva non si carica automaticamente /etc/profile
e ~/.profile
.Penso che il motivo per cui le persone fanno questo sia per gli utenti che accedono tramite una GUI (un caso molto comune) e che inseriscono le impostazioni delle variabili di ambiente .bash_profile
anziché .profile
. La maggior parte dei meccanismi di accesso alla GUI invoca .profile
ma non .bash_profile
(la lettura .bash_profile
richiederebbe l'esecuzione di bash come parte dell'avvio della sessione, anziché di sh). Con questa configurazione, quando l'utente apre un terminale, otterrà le variabili di ambiente. Tuttavia, l'utente non otterrà le variabili di ambiente nelle applicazioni GUI, che è una fonte di confusione molto comune. La soluzione qui è utilizzare .profile
invece di .bash_profile
impostare le variabili di ambiente. L'aggiunta di un ponte tra .bashrc
e .bash_profile
crea più problemi di quanti ne risolva.
Esiste un modo semplice e portatile per verificare se la shell corrente è interattiva: verificare se l'opzione -i
è abilitata.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
Questo è utile .bashrc
per leggere .profile
solo se la shell non è interattiva - cioè il contrario di ciò che fa il codice! Leggi .profile
se bash è una shell di accesso (non interattiva) e non leggerla se è una shell interattiva.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
[[ -o interactive ]]
(ksh, bash, zsh) o case $- in (*i*) ...; esac
(POSIX)
PS1
se non eseguito in modo interattivo. È abbastanza facile da testare: PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
non stampa nulla, mentre PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
stampa il valore di $PS1
set nei file di avvio di bash (non stampa la stringa "cuculo").
$-
contenga i
con una shell interattiva.
[ -n "${PS1}" ]
sbagliato va un po 'troppo lontano, dopo tutto si interrompe solo quando qualcuno esporta PS1 (che nella tua risposta dici che è una cattiva idea e anche andare nei motivi per cui) e questo non influisce bash comunque (poiché disinserisce PS1 e PS2 se la shell non è interattiva). Forse usare una parola come "scoraggiato" o parlare dei "limiti" dell'approccio sarebbe stato migliore. Non penso che sia "sbagliato" del tutto. Se qualcosa non va nell'esportazione di PS1, questo è certo! Comunque, grazie per essere entrato nei dettagli di questo.
Sembra che questo strano concetto sia il risultato del fatto che bash
non è iniziato come un clone della shell POSIX ma come un Bourne Shell
clone.
Di conseguenza, il comportamento interattivo POSIX ( $ENV
viene chiamato per shell interattive) è stato aggiunto in seguito bash
e non è ampiamente noto.
C'è una shell che garantisce un comportamento simile. Questo è csh
e csh concede che $prompt
ha valori specifici:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
Ma ciò non si applica né alla Bourne Shell né alle shell POSIX.
Per una shell POSIX, l'unico metodo concesso è inserire il codice per le shell interattive nel file:
$ENV
che ha un nome specifico della shell. È ad es
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Altre persone hanno menzionato il flag shell -i
, ma questo non è utilizzabile per una programmazione affidabile. POSIX non richiede che set -i
funzioni, né che $-
contenga una i
shell interattiva. POSIX richiede solo che sh -i
imposti la shell in modalità interattiva.
Poiché la variabile $PS1
può essere importata dall'ambiente, può avere un valore anche in modalità non interattiva. Il fatto che bash
unset
s PS1
in qualsiasi shell non interattiva non è concesso dalla norma e non fatto da qualsiasi altra shell.
Quindi una programmazione pulita (anche con bash
) è quella di inserire i comandi per le shell interattive $HOME/.bashrc
.
Per prima cosa parlerò di ciò che Debian, e la maggior parte delle volte anche Ubuntu imposta per bash. E quest'ultimo tocco su altri sistemi.
Nell'impostazione dei file di avvio della shell c'è molta opinione.
Ho anche la mia opinione ma cercherò di mostrare esempi esistenti di impostazioni corrette.
Userò debuan in quanto è abbastanza facile trovare esempi dei suoi file.
E debian è molto usato, quindi le impostazioni sono state ben testate,
Solo per scoprire se la shell è interattiva.
L' impostazione predefinita /etc/profile
in debian e ubuntu (da / usr / share / base-files / profile):
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
L'if è di lettura: if interattivo (set di impostazioni predefinite PS1) ed è una shell bash (ma non funziona come impostazione predefinita sh
) quindi cambia PS1 con una nuova (non quella predefinita).
L' impostazione predefinita /etc/bash.bashrc
in debian contiene anche:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Il che è abbastanza chiaro in ciò che fa: se interattivo non fonte (il resto).
Tuttavia, in /etc/skel/.bashrc
è un esempio del modo corretto di testare una shell interattiva (usando $-
):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Ciò dovrebbe mostrare chiaramente il perché di PS1 e un'alternativa.
L'impostazione che stai segnalando dovrebbe essere evitata.
L'ordine (da impostazioni di sistema alle impostazioni utente più specifiche (per bash)) è /etc/profile
, /etc/bash.bashrc
, ~/.profile
e infine ~/.bashrc
. Questo posiziona gli effetti più ampi (e per più shell) in /etc/profile
(che è di proprietà di root) seguito da /etc/bash.bashrc
(che è anche di proprietà di root) ma influenza solo bash. Poi arrivano le impostazioni personali $HOME
, la prima è ~/.profile
per la maggior parte delle shell e ~/.bashrc
(quasi equivalente a ~/.bash_profile
), specifica solo per bash.
E 'quindi sbagliato fonte ~/.bashrc
in ~/.profile
, si sta trasformando una impostazione bash per un più generale che è specifico utente interessando più conchiglie . Tranne se fatto in questo modo :
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
Verifica che bash sia in esecuzione e si carica solo in .bashrc
questo caso.
Questa è una decisione a monte proveniente da Debian. La logica è spiegata qui .
In effetti, il contrario, l'approvvigionamento ~/.profile
di ~/.bash_profile
(o ~/.bashrc
) sta solo riapplicando regole generali che avrebbero dovuto essere già caricate in un caso d'uso particolare, e quindi "non così male" (non sto dicendo "buono"). E non sto dicendo bene perché potrebbe causare il looping del sourcing dei file. Come quando una sottodirectory carica un genitore, questo è un ciclo di directory.
Ed è in questo approvvigionamento incrociato che ha senso il controllo della shell interattiva. Solo quando una shell è interattiva viene ~/.bashrc
caricata, ma a sua volta può essere in fase di caricamento ~/.profile
(o viceversa) ed è in questo caso che è possibile utilizzare il controllo di una shell interattiva.
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )
, che semplicemente stampa[]
. Sembra zsh non fare lo stesso, almeno da un esperimento ... In ogni caso, l' intento della[ -n "$PS1" ]
è quello di verificare se la shell è interattiva o meno.