So definieren Sie eine Bash-Funktion, die von verschiedenen Skripten verwendet werden kann

13

Ich habe bashin meiner ~/.bashrcDatei eine Funktion definiert . Dies ermöglicht mir die Verwendung in Shell-Terminals. Es scheint jedoch nicht zu existieren, wenn ich es aus einem Skript heraus aufrufe.

Wie kann ich eine bashFunktion definieren , die auch von Skripten verwendet wird?

Onturenio
quelle
Aber mein .bash_profile liest grundsätzlich die .basrc-Datei, so dass ich erwarten würde, dass das Ergebnis das gleiche ist, unabhängig davon, ob ich eine Login- oder eine Nicht-Login-Shell verwende.
Onturenio
Verwenden Sie /bin/shin der Shebang-Linie?
Kevin

Antworten:

9

~/.bash_profileund ~/.bashrcwerden nicht von Skripten gelesen, und Funktionen werden standardmäßig nicht exportiert. Dazu können Sie export -fwie folgt vorgehen:

$ cat > script << 'EOF'
#!/bin/bash
foo
EOF
$ chmod a+x script
$ ./script
./script: line 2: foo: command not found
$ foo() { echo "works" ; } 
$ export -f foo
$ ./script
works

export -f fookönnte auch aufgerufen werden ~/.bash_profile, um diese Funktion nach der Anmeldung für Skripte verfügbar zu machen. Seien Sie gewarnt, dass export -fes nicht tragbar ist.

Eine bessere Lösung wäre es, die Datei, die die Funktion enthält, mit zu beschaffen . file. Dies ist viel portabler und setzt nicht voraus, dass Ihre Umgebung auf eine bestimmte Weise eingerichtet wird.

Chris Down
quelle
Warum nicht einfach eine Funktion wie function myFunction { ... }in deklarieren ~/.bash_profileund loslegen?
Amphibient
Wenn ich Ihre Antwort richtig verstehe (in Bezug auf die Beschaffung einer Datei mit der Funktion), würde dies bedeuten, dass ich die Datei explizit in jedem Skript angeben muss, was ziemlich ärgerlich ist. Dies ist nicht viel unkomplizierter als das Einfügen der Funktion in jedes Skript. Ich würde natürlich ein paar Zeilen sparen, aber das ist alles. Die exportLösung scheint jedoch ordnungsgemäß zu funktionieren. Vielen Dank.
Onturenio
@foampile, genau das habe ich gemacht und funktioniert nicht, wenn ich die Funktion von einem Skript aus aufrufe.
Onturenio
1
@Onturenio: Die zweite Methode, die @ chris-down vorschlägt, ist in der Tat besser: 1) Wenn jemand das Skript liest, weiß er, dass es eine fooFunktion von einer anderen benötigt. file2) Sie können den Inhalt davon besser kontrollieren, fileals sicherzustellen, dass die aufrufende Shell hat sich foovor dem Aufruf Ihres Skripts nicht geändert . Sie können beispielsweise Sicherheitsüberprüfungen hinzufügen file, um sicherzustellen, dass keine Manipulation vorliegt. (nicht einfach, aber möglich). (na ja, du könntest auch die definierte foo-Funktion überprüfen ... aber du bekommst meine Drift ^^ Ich denke, die Methode 2 ist sauberer.) 3) filewird nur das enthalten, was benötigt wird, nicht mehr.
Olivier Dulac
8

.bashrcwird nur von interaktiven Shells gelesen. (Eigentlich ist das eine Vereinfachung: Bash ist in dieser Hinsicht eigenartig. Bash liest nicht, .bashrcob es sich um eine interaktive oder nicht interaktive Anmeldeshell handelt. Und es gibt auch eine Ausnahme: Wenn der übergeordnete Prozess von Bash rshdoder ist sshd, dann liest Bash .bashrc, ob es interaktiv ist oder nicht.)

Platzieren Sie Ihre Funktionsdefinitionen in einer Datei an einem bekannten Ort und verwenden Sie die .(auch geschriebene source) Funktion, um diese Datei in ein Skript aufzunehmen.

$ cat ~/lib/bash/my_functions.bash
foo () {

$ cat ~/bin/myscript
#!/bin/bash
. ~/lib/bash/my_functions.bash
foo bar

Wenn Sie möchten, können Sie die Autoload-Funktion von ksh verwenden. Fügen Sie jede Funktionsdefinition in eine Datei mit demselben Namen wie die Funktion ein. Listen Sie die Verzeichnisse mit den Funktionsdefinitionen in der FPATHVariablen auf (eine durch Doppelpunkte getrennte Liste von Verzeichnissen). Hier ist eine grobe Annäherung an kshs, autoloaddie die Funktion tatsächlich sofort statt nach Bedarf lädt:

autoload () {
  set -- "$(set +f; IFS=:;
            for d in $FPATH; do
              if [ -r "$d/$1" ]; then echo -E "$d/$1"; break; fi;
            done)"
  [[ -n $1 ]] && . "$1"
}
Gilles 'SO - hör auf böse zu sein'
quelle
+1 für Autoload, obwohl ich die mit bash mitgelieferten empfehle. Die neueste Version unterstützt Lazy Load.
Seestern
0

Haben Sie benötigen eine Funktion? Wenn nicht, ziehen Sie in Betracht, die Logik in ein separates, eigenständiges Bash-Skript in Ihrem zu ziehen $PATH. Zum Beispiel hatte ich das in meinem ~/.bashrc:

# echo public IP address
alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'

~/binist in meinem $PATH, also habe ich ~/bin/wanipmit folgendem inhalt erstellt:

#!/bin/bash

# echo public IP address
dig +short myip.opendns.com @resolver1.opendns.com

Und lief chmod 0755 ~/bin/wanip, um es ausführbar zu machen. Jetzt kann ich wanipvon anderen Skripten ausführen .

Ich mag es, wanipein eigenständiges Bash-Skript zu haben. Es erinnert mich daran, dass ich möchte, dass diese Logik allgemein verfügbar ist (außer in meiner aktuellen interaktiven Bash-Sitzung). Das Skript kapselt die Logik und Dokumentation dafür.

Adam Monsen
quelle