.Bashrc kann nicht erfolgreich aus einem Shell-Skript bezogen werden

51

Normalerweise können wir ~/.bashrcmit diesem Befehl eine Quelldatei erstellen

source ~/.bashrc

Aber wenn ich dies in ein Shell-Skript schreibe und es ausführe, passiert nichts. Warum?
Gibt es eine Möglichkeit, dies zu tun?

Mein Drehbuch:

#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc

Auch versucht .(Punkt) statt source. Gleiches Ergebnis.

Shantanu
quelle

Antworten:

26

Ein Shell-Skript wird in einer eigenen Shell-Instanz ausgeführt. Alle Variableneinstellungen, Funktionsdefinitionen und dergleichen wirken sich nur auf diese Instanz (und möglicherweise auf deren untergeordnete Instanzen) aus, nicht jedoch auf die aufrufende Shell, sodass sie nach Abschluss des Skripts nicht mehr vorhanden sind.

Im Gegensatz dazu sourcestartet der Befehl keine neue Shell-Instanz, sondern verwendet die aktuelle Shell, sodass die Änderungen erhalten bleiben.

Wenn Sie möchten, dass eine Verknüpfung Ihre .bashrc-Datei liest, verwenden Sie eine Shell-Funktion oder einen Alias ​​anstelle eines Shell-Skripts wie

alias brc='source ~/.bashrc'
Florian Diesch
quelle
Danke für deine schnelle Antwort. Ihre Lösung funktioniert vielleicht, aber ich muss die bashrc-Datei manuell bearbeiten, um die Zeile 'aliac brc = ....' zu speichern. Ich versuche eine GUI zu entwickeln, um die Umgebungsvariable zu ändern. Daher kann ich die bashrc-Datei eines anderen Computers nicht manuell bearbeiten.
Shantanu
1
Sie müssen source ~/.bashrcin der Shell ausgeführt werden, deren Umgebung Sie ändern möchten. Sie können es nicht von einem anderen Prozess aus ändern. Möglicherweise kann das Hinzufügen dieses Alias ​​(global) Teil des Installationsprozesses Ihrer GUI sein.
Florian Diesch
1
Muss ich Ihren Alias-Befehl früher in das Skript einfügen und dann brc aufrufen, wenn ich meine .bashrc-Datei als Quelle verwenden möchte, oder muss ich diesen Alias-Befehl irgendwo in eine Datei einfügen?
user137717
Am Ende habe ich Florian Dieschs Antwort erweitert. Sie könnten einfach einen mehrzeiligen Alias ​​verwenden: alias brc = 'chmod a + x ~ / .bashrc; source ~ / .bashrc 'Ich bin noch ziemlich neu, daher bin ich mir nicht sicher, ob dies als' schlechte Praxis 'angesehen wird. Es funktioniert aber.
A_user_appears
13

Ihr .bashrcfängt normalerweise an:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Da für Ihr Skript PS1 nicht festgelegt ist (da es nicht interaktiv ist), wird der Pfad nicht zurückgesetzt, da es vorzeitig beendet wird. Ändern Sie zur Demonstration Ihr Skript:

    #!/bin/bash
    chmod a+x ~/.bashrc
    PS1='$ '
    source ~/.bashrc

Dadurch können Ihre Skripte jetzt mit dem neuen arbeiten .bashrc. Hinweis: Sobald Ihr Skript beendet ist, wird die env auf den Stand vor dem Starten des Skripts gesetzt. Die Änderungen werden beim nächsten Start eines Terminals übernommen.

Ravi Nankani
quelle
Spätestens seit 16.04 und wahrscheinlich früher .bashrcverwendet Ubuntu eine zuverlässigere Methode, um zu überprüfen, ob die Shell interaktiv ist. /etc/bash.bashrchat noch den PS1 Test.
Zanna
12

Versuchen:

exec bash

Dies sollte ~ / .bashrc, ~ / .bash_aliases usw. neu laden.

Alin Andrei
quelle
9
Dies ersetzt den aktuellen Bash-Prozess durch einen neuen. Es ist nicht viel kürzer oder einfacher als die Verwendung source, zerstört aber alle Variablen und zwar so, dass der Benutzer sie manuell eingestellt hat - was auch immer Sie wollen oder nicht.
Florian Diesch
Moment mal, setzen Sie im Kontext eines Shell-Skripts mit anderen Befehlen nach dem bashrc-Sourcing die Befehle, die danach den neuen bash-Status benötigen, so exec bash, wie ich es verstehe, in die gleichen bash-Einstellungen wie zuvor?
Tatsu
11

Ich möchte Ravis Antwort ergänzen :

Dieses Verhalten ist spezifisch für Ubuntu (und wahrscheinlich die meisten abgeleiteten Distributionen), da Ihre Standarddatei ~/.bashrcmit einem Kurzschluss beginnt, beispielsweise Ubuntu 18.04:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Dadurch wird die Auswertung der Datei gestoppt, wenn sie in einer nicht interaktiven Shell ausgeführt wird, wie dies bei Ihrem Skript der Fall ist, da alle Skripts in einer nicht interaktiven Shell ausgeführt werden , und anschließend jede Datei, die Sie sourcediese Eigenschaft erben.

eval hacken

Ich habe einen hässlichen Hack gefunden, um Ubuntu speziell zu umgehen, indem ich evalanstelle von source:

eval "$(cat ~/.bashrc | tail -n +10)"

Es überspringt einfach die wenigen ersten Zeilen und wertet den Rest aus, ~/.bashrcso dass der Rest ausgewertet wird und die aktuelle Ausführung ändert.

Beachten Sie, dass es sich um eine magische Zahl handelt und möglicherweise nicht für alle Ubuntu-Versionen funktioniert. Dies kann jedoch eine gute Lösung sein, wenn Sie Skripte für mehr oder weniger bekannte Systeme erstellen.

Eine schickere Lösung könnte darin bestehen, Regex zu verwenden, um auf die spezifischen Bits abzuzielen, die die Auswertung stoppen.

Shebang Alternative

Eine andere Alternative, die in einigen Szenarien möglicherweise besser funktioniert, besteht darin, das Skript zur Ausführung in einer interaktiven Shell zu zwingen, indem im shebang ein Flag hinzugefügt wird :

#!/bin/bash -i

Seien Sie sich einiger Dinge bewusst:

  • Es ist besser , das #!/usr/bin/env bashFormular zu verwenden, aber auf diese Weise können Sie die Shell nicht mit Argumenten starten .
  • Das Verwenden von -ihat seine eigenen Konsequenzen, unter anderem werden Programme zur Benutzerinteraktion aufgefordert, und dies ist normalerweise nicht für Skripte gedacht. Wenn Sie beispielsweise debPakete installieren , wird das Skript möglicherweise bei Eingabeaufforderungen dpkg configureangehalten .
  • Ich habe anfangs versucht, die Funktion dort zu verwenden set -iund set +izu deaktivieren, wo ich sie brauchte, aber das funktioniert nicht .
stefanmarisch
quelle
2

Keine der anderen Methoden funktionierte für mich [ source /path/to/filevs . ./path/to/file, alias, etc ...], bis ich dank dieses Tutorials Folgendes fand:

#!/usr/bin/env bash shebang

Anstelle der einfacheren #!/usr/bin/envMethode können Argumente an den Interpreter weitergeleitet werden, der meiner Meinung nach der Schlüssel ist. Weitere Informationen finden Sie in diesem Dokument .

In jedem Fall, wenn Quellbefehle in irgendeiner Form für Sie nicht funktionieren, versuchen Sie, Ihren shebang zu überprüfen, das könnte das Problem sein :)

Nikksno
quelle