Welchen Zweck erfüllt das [ -n "$PS1" ]
In [ -n "$PS1" ] && source ~/.bash_profile;
? Diese Zeile ist in .bashrc
einem Dotfiles- Repo enthalten .
Welchen Zweck erfüllt das [ -n "$PS1" ]
In [ -n "$PS1" ] && source ~/.bash_profile;
? Diese Zeile ist in .bashrc
einem Dotfiles- Repo enthalten .
Antworten:
Hiermit wird überprüft, ob die Shell interaktiv ist oder nicht. In diesem Fall wird die ~/.bash_profile
Datei nur bezogen, wenn die Shell interaktiv ist.
Siehe "Ist diese Shell interaktiv?" im Bash-Handbuch, das diese spezifische Redewendung zitiert. (Es wird außerdem empfohlen, zu überprüfen, ob die Shell interaktiv ist, indem getestet wird, ob die $-
spezielle Variable das i
Zeichen enthält. Dies ist ein besserer Ansatz für dieses Problem.)
bash
Deaktivieren von PS1, wenn es nicht interaktiv ist (Tippfehler in Ihrem vorherigen Kommentar), ist ein IMO-Fehler. PS1 ist keine Bash-spezifische Variable. Es hat kein Geschäft, es zu deaktivieren. Dies ist die einzige Shell, die dies tut (obwohl sie yash
auch dann PS1
auf einen Standardwert gesetzt wird, wenn sie nicht interaktiv ist).
[[ $- = *i* ]] && source ~/.bash_profile
).
[ -n "${PS1}" ]
, aber ich habe meine Antwort immer noch aktualisiert, um hervorzuheben, dass das Bash-Handbuch auch eine Inspektion vorschlägt / empfiehlt, $-
um festzustellen, ob die Shell interaktiv ist. Ich hoffe, Sie finden, dass dies die Antwort verbessert. Prost!
Dies ist eine weit verbreitete Methode, um zu testen, ob die Shell interaktiv ist. Beachten Sie, dass es nur in Bash funktioniert, nicht mit anderen Shells. Es ist also in Ordnung (wenn auch albern) .bashrc
, aber es würde nicht funktionieren .profile
(was von sh gelesen wird und bash ist nur eine der möglichen Implementierungen von sh und nicht die häufigste).
Eine interaktive Shell setzt die Shell-VariablePS1
auf die Standard-Eingabeaufforderungszeichenfolge. Wenn die Shell also interaktiv ist, PS1
ist sie festgelegt (es sei denn, der Benutzer .bashrc
hat sie entfernt, was oben noch nicht geschehen ist .bashrc
, und Sie könnten davon ausgehen, dass dies sowieso eine dumme Sache ist).
Das Gegenteil ist in bash der Fall: Nicht interaktive Instanzen von bash werden PS1
beim Start nicht gesetzt. Beachten Sie, dass dieses Verhalten spezifisch für Bash ist und möglicherweise ein Fehler ist (warum sollte es bash -c '… do stuff with $var…'
nicht funktionieren, wenn es var
ist PS1
?). Aber alle Versionen von Bash bis einschließlich 4.4 (die neueste Version, wie ich sie schreibe) tun dies.
Viele Systeme exportieren PS1
in die Umwelt. Es ist eine schlechte Idee, da viele verschiedene Shells PS1
eine andere Syntax verwenden (z. B. unterscheiden sich die Eingabeaufforderungen von bash von den Eingabeaufforderungen von zsh vollständig ). Es ist jedoch weit genug verbreitet, dass das Festlegen in der Praxis PS1
kein verlässlicher Indikator dafür ist, dass die Shell interaktiv ist. Die Shell hat möglicherweise PS1
von der Umgebung geerbt .
.bashrc
ist die Datei, die Bash beim Start liest, wenn sie interaktiv ist. Eine weniger bekannte Tatsache ist, dass bash auch .bashrc
eine Anmeldeshell liest und die Heuristiken von bash zu dem Schluss kommen, dass es sich um eine Remote-Sitzung handelt (bash prüft, ob das übergeordnete Element rshd
oder ist sshd
). In diesem zweiten Fall ist es unwahrscheinlich, dass PS1
dies in der Umgebung festgelegt wird, da noch keine Punktdatei ausgeführt wurde.
Die Art und Weise, wie der Code diese Informationen verwendet, ist jedoch kontraproduktiv.
.bash_profile
in dieser Shell ausgeführt. Ist .bash_profile
aber ein Login-Time-Skript. Möglicherweise werden einige Programme ausgeführt, die nur einmal pro Sitzung ausgeführt werden sollen. Möglicherweise werden einige Umgebungsvariablen überschrieben, die der Benutzer vor dem Ausführen dieser Shell absichtlich auf einen anderen Wert festgelegt hat. Das Ausführen .bash_profile
in einer Shell ohne Anmeldung ist störend..bash_profile
. Dies ist jedoch der Fall, wenn das Laden .bash_profile
nützlich sein kann, da eine nicht interaktive Anmeldeshell nicht automatisch geladen wird /etc/profile
und ~/.profile
.Ich denke , der Grund , warum Menschen diese für die Nutzer zu tun ist , die sich anmelden über eine GUI (eine sehr häufige Fall) und die ihre Einstellungen der Umgebungsvariablen setzen in .bash_profile
statt .profile
. Die meisten GUI-Anmeldemechanismen rufen auf, .profile
aber nicht .bash_profile
(das Lesen .bash_profile
würde das Ausführen von bash als Teil des Sitzungsstarts anstelle von sh erfordern). Wenn der Benutzer bei dieser Konfiguration ein Terminal öffnet, erhält er seine Umgebungsvariablen. Der Benutzer erhält seine Umgebungsvariablen jedoch nicht in GUI-Anwendungen, was sehr häufig zu Verwirrung führt. Die Lösung besteht darin, Umgebungsvariablen zu verwenden, .profile
anstatt sie .bash_profile
festzulegen. Das Hinzufügen einer Brücke zwischen .bashrc
und .bash_profile
schafft mehr Probleme als es löst.
Es gibt eine einfache, tragbare Methode, um zu testen, ob die aktuelle Shell interaktiv ist: Testen Sie, ob die Option -i
aktiviert ist.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
Dies ist nützlich .bashrc
, um .profile
nur zu lesen , wenn die Shell nicht interaktiv ist - dh das Gegenteil von dem, was der Code tut! Lesen Sie, .profile
ob bash eine (nicht interaktive) Anmeldeshell ist, und lesen Sie es nicht, wenn es sich um eine interaktive Shell handelt.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
[[ -o interactive ]]
(ksh, bash, zsh) oder case $- in (*i*) ...; esac
(POSIX)
PS1
wenn sie nicht interaktiv ausgeführt wird. Es ist einfach zu testen: PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
druckt nichts, während PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
der Wert von $PS1
set in Ihren Bash-Startdateien gedruckt wird (es wird nicht die Zeichenfolge "cuckoo" gedruckt).
$-
enthält i
eine interaktive Shell.
[ -n "${PS1}" ]
falsches Anrufen etwas zu weit geht, schließlich bricht es nur ab, wenn jemand PS1 exportiert (was Sie in Ihrer Antwort als schlechte Idee bezeichnen und sogar auf die Gründe dafür eingehen), und das hat keinen Einfluss Bash sowieso (da es PS1 und PS2 deaktiviert, wenn die Shell nicht interaktiv ist.) Vielleicht wäre es besser gewesen, ein Wort wie "entmutigt" zu verwenden oder über die "Einschränkungen" des Ansatzes zu sprechen. Ich denke nicht, dass es insgesamt "falsch" ist. Wenn beim Exportieren von PS1 etwas nicht stimmt, ist das sicher! Wie auch immer, danke, dass Sie auf die Details eingegangen sind.
Es scheint, dass dieses seltsame Konzept auf die Tatsache zurückzuführen ist, dass bash
es nicht als POSIX-Shell-Klon, sondern als Bourne Shell
Klon gestartet wurde .
Infolgedessen wurde das interaktive Verhalten von POSIX ( $ENV
wird für interaktive Shells aufgerufen) später hinzugefügt bash
und ist nicht allgemein bekannt.
Es gibt eine Shell, die ein ähnliches Verhalten zulässt. Dies ist csh
und csh gewährt, $prompt
die bestimmte Werte hat:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
Dies gilt jedoch weder für die Bourne-Shell noch für POSIX-Shells.
Für eine POSIX-Shell besteht die einzige gewährte Methode darin, Code für interaktive Shells in die Datei einzufügen:
$ENV
das hat einen Shell-spezifischen Namen. Es ist zB
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Andere Leute erwähnten das Shell-Flag -i
, aber dies ist für eine zuverlässige Programmierung nicht verwendbar. POSIX erfordert weder, dass dies set -i
funktioniert, noch dass es $-
eine i
für interaktive Shells enthält. POSIX erfordert lediglich, dass sh -i
die Shell in den interaktiven Modus versetzt wird.
Da die Variable $PS1
aus der Umgebung importiert werden kann, kann sie auch im nicht interaktiven Modus einen Wert haben. Die Tatsache, dass bash
unset
s PS1
in einer nicht interaktiven Shell enthalten ist, wird vom Standard nicht gewährt und von keiner anderen Shell ausgeführt.
Saubere Programmierung (auch mit bash
) bedeutet also, die Befehle für interaktive Shells einzugeben $HOME/.bashrc
.
Ich werde zuerst darüber sprechen, was Debian ist, und die meiste Zeit setzt auch Ubuntu auf Bash. Und letztere berühren andere Systeme.
Bei der Einstellung von Shell-Startdateien gibt es viele Meinungen.
Ich habe auch meine Meinung, aber ich werde versuchen, vorhandene Beispiele für korrekte Einstellungen zu zeigen.
Ich werde Debuan verwenden, da es ziemlich einfach ist, Beispiele für seine Dateien zu finden.
Und Debian wird häufig verwendet, daher wurden die Einstellungen gut getestet.
Nur um herauszufinden, ob die Shell interaktiv ist.
Die Standardeinstellung /etc/profile
in Debian und Ubuntu (aus / usr / share / base-files / profile):
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
Das if lautet: Wenn interaktiv (PS1-Standard festgelegt) und es sich um eine Bash-Shell handelt (die jedoch nicht als Standard fungiert sh
), ändern Sie PS1 in eine bestimmte neue (nicht die Standard- Shell ).
Die Standardeinstellung /etc/bash.bashrc
in Debian enthält außerdem:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Was ziemlich klar ist, was es tut: Wenn interaktiv nicht beschaffen (der Rest).
Jedoch in /etc/skel/.bashrc
ist ein Beispiel der richtigen Art und Weise zu Test für eine interaktive Shell (mit $-
):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Das sollte klar zeigen, warum PS1 und eine Alternative.
Die Einstellung, die Sie melden, sollte vermieden werden.
Die Reihenfolge (von Systemeinstellungen auf spezifischere Benutzereinstellungen (für bash)) ist /etc/profile
, /etc/bash.bashrc
, ~/.profile
und schließlich ~/.bashrc
. Dadurch werden die breitesten Effekte (und für mehr Shells) in /etc/profile
(die Root gehören) gefolgt von /etc/bash.bashrc
(die auch Root gehören) platziert, aber nur Bash beeinflusst. Dann kommen die persönlichen Einstellungen $HOME
, die erste ist ~/.profile
für die meisten Muscheln und ~/.bashrc
(fast gleichbedeutend mit ~/.bash_profile
) nur für Bash spezifisch.
Es ist daher falsch zu Quelle ~/.bashrc
in ~/.profile
, es einen bestimmten Benutzer für bash auf eine allgemeinere Einstellung verwandelt , die sich mehr Schalen zu beeinflussen . Außer wenn dies folgendermaßen gemacht wird :
# ~/.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
Es überprüft, ob bash ausgeführt wird und lädt nur, .bashrc
wenn dies der Fall ist.
Dies ist eine vorgelagerte Entscheidung von Debian. Die Begründung wird hier erläutert .
Umgekehrt werden bei der Beschaffung ~/.profile
in ~/.bash_profile
(oder ~/.bashrc
) nur allgemeine Regeln erneut angewendet, die bereits auf einen bestimmten Anwendungsfall geladen werden sollten, und daher "nicht so schlecht" (ich sage nicht "gut"). Und ich sage nicht gut, weil es dazu führen kann, dass sich das Sourcing von Dateien wiederholt. Wie wenn ein Unterverzeichnis ein übergeordnetes Element lädt, ist dies eine Verzeichnisschleife.
Und in diesem Cross-Sourcing macht die Prüfung auf interaktive Shell Sinn. Nur wenn eine Shell interaktiv ist ~/.bashrc
, wird sie geladen, aber sie wird möglicherweise geladen ~/.profile
(oder umgekehrt). In diesem Fall kann die Suche nach einer interaktiven Shell verwendet werden.
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )
dem einfach gedruckt wird[]
. Es scheint , zsh nicht das gleiche tun, zumindest aus einem Experiment ... In jedem Fall ist die Absicht der[ -n "$PS1" ]
zu prüfen ist , ob die Shell interaktiv ist oder nicht.