In zsh definiert der Funktionssuchpfad ($ fpath) eine Reihe von Verzeichnissen, die Dateien enthalten, die zum automatischen Laden markiert werden können, wenn die darin enthaltene Funktion zum ersten Mal benötigt wird.
Zsh bietet zwei Modi zum automatischen Laden von Dateien: den systemeigenen Modus von Zsh und einen anderen Modus, der dem automatischen Laden von ksh ähnelt. Letzteres ist aktiv, wenn die Option KSH_AUTOLOAD gesetzt ist. Der native Modus von Zsh ist die Standardeinstellung, und ich werde hier nicht auf die andere Weise eingehen (siehe "man zshmisc" und "man zshoptions" für Details zum automatischen Laden im ksh-Stil).
Okay. Angenommen, Sie haben ein Verzeichnis "~ / .zfunc" und möchten, dass es Teil des Funktionssuchpfads ist. Gehen Sie dazu folgendermaßen vor:
fpath=( ~/.zfunc "${fpath[@]}" )
Das fügt Ihr privates Verzeichnis an der Spitze des Suchpfads hinzu. Dies ist wichtig, wenn Sie Funktionen aus der Installation von zsh mit Ihren eigenen überschreiben möchten (z. B. wenn Sie eine aktualisierte Vervollständigungsfunktion wie _git aus dem CVS-Repository von zsh mit einer älteren installierten Version der Shell verwenden möchten).
Es ist auch erwähnenswert, dass die Verzeichnisse von $ fpath nicht rekursiv durchsucht werden. Wenn Sie möchten, dass Ihr privates Verzeichnis rekursiv durchsucht wird, müssen Sie sich selbst darum kümmern (für das folgende Snippet muss die Option EXTENDED_GLOB gesetzt sein):
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
Es sieht für das ungeübte Auge vielleicht kryptisch aus, fügt aber wirklich nur alle Verzeichnisse unterhalb von ~ / .zfunc zu $ fpath hinzu, während Verzeichnisse mit dem Namen "CVS" ignoriert werden (was nützlich ist, wenn Sie vorhaben, ein Ganzes auszuchecken Funktionsbaum aus dem CVS von zsh in Ihren privaten Suchpfad).
Nehmen wir an, Sie haben eine Datei "~ / .zfunc / hello", die die folgende Zeile enthält:
printf 'Hello world.\n'
Alles, was Sie jetzt tun müssen, ist , die Funktion zu markieren, die bei ihrer ersten Referenz automatisch geladen werden soll:
autoload -Uz hello
"Worum geht es in der -Uz?", Fragst du? Nun, das ist nur eine Reihe von Optionen, die dazu führen, dass "Autoload" das Richtige tut, unabhängig davon, welche Optionen ansonsten eingestellt werden. Das "U" deaktiviert die Alias-Erweiterung, während die Funktion geladen wird, und das "z" erzwingt das automatische Laden im Stil von "zsh", auch wenn "KSH_AUTOLOAD" aus irgendeinem Grund festgelegt ist.
Nachdem dies erledigt wurde, können Sie Ihre neue "Hallo" -Funktion verwenden:
zsh% hallo
Hallo Welt.
Ein Wort zur Beschaffung dieser Dateien: Das ist einfach falsch . Wenn Sie diese `~ / .zfunc / hello'-Datei als Quelle verwenden, wird nur" Hallo Welt "gedruckt. Einmal. Nichts mehr. Es wird keine Funktion definiert. Außerdem besteht die Idee darin, den Funktionscode nur dann zu laden, wenn er benötigt wird . Nach dem Aufruf von `autoload 'wird die Definition der Funktion nicht gelesen. Die Funktion ist nur markiert, um später bei Bedarf automatisch geladen zu werden.
Zum Schluss noch ein Hinweis zu $ FPATH und $ fpath: Zsh behält diese als verknüpfte Parameter bei. Der Parameter in Kleinbuchstaben ist ein Array. Die Großbuchstabenversion ist ein String-Skalar, der die Einträge aus dem verknüpften Array enthält, die durch Doppelpunkte zwischen den Einträgen verbunden sind. Dies geschieht, weil der Umgang mit einer Liste von Skalaren mit Arrays viel natürlicher ist und gleichzeitig die Abwärtskompatibilität für Code aufrechterhalten wird, der den Parameter scalar verwendet. Wenn Sie sich für die Verwendung von $ FPATH (dem skalaren) entscheiden, müssen Sie vorsichtig sein:
FPATH=~/.zfunc:$FPATH
wird funktionieren, während die folgenden nicht:
FPATH="~/.zfunc:$FPATH"
Der Grund dafür ist, dass die Tilde-Erweiterung nicht in doppelten Anführungszeichen erfolgt. Dies ist wahrscheinlich die Ursache Ihrer Probleme. Wenn echo $FPATH
eine Tilde und kein erweiterter Pfad gedruckt wird, funktioniert dies nicht. Aus Sicherheitsgründen würde ich $ HOME anstelle einer Tilde wie folgt verwenden:
FPATH="$HOME/.zfunc:$FPATH"
Davon abgesehen würde ich den Array-Parameter viel lieber verwenden, wie ich es oben in dieser Erklärung getan habe.
Sie sollten den Parameter $ FPATH auch nicht exportieren. Es wird nur vom aktuellen Shell-Prozess und nicht von einem seiner untergeordneten Elemente benötigt.
Aktualisieren
Bezüglich des Inhalts von Dateien in "$ fpath":
Beim automatischen Laden im Stil von zsh ist der Inhalt einer Datei der Hauptteil der von ihr definierten Funktion. Somit definiert eine Datei mit dem Namen "hallo", die eine Zeile enthält, echo "Hello world."
vollständig eine Funktion mit dem Namen "hallo". Es steht Ihnen frei,
hello () { ... }
den Code zu umgehen, aber das wäre überflüssig.
Die Behauptung, dass eine Datei nur eine Funktion enthalten darf, ist jedoch nicht ganz richtig.
Insbesondere wenn Sie sich einige Funktionen des funktionsbasierten Vervollständigungssystems (compsys) ansehen, werden Sie schnell feststellen, dass dies ein Missverständnis ist. Sie können zusätzliche Funktionen in einer Funktionsdatei definieren. Sie können auch jede Art von Initialisierung durchführen, die Sie möglicherweise beim ersten Aufruf der Funktion durchführen müssen. Wenn Sie dies jedoch tun, definieren Sie immer eine Funktion, die wie die Datei in der Datei benannt ist, und rufen diese Funktion am Ende der Datei auf, damit sie beim ersten Aufrufen der Funktion ausgeführt wird.
Wenn Sie bei Unterfunktionen keine Funktion definiert haben, die wie die Datei in der Datei benannt ist, enthält diese Funktion Funktionsdefinitionen (dh die Unterfunktionen in der Datei). Sie würden effektiv alle Ihre Unterfunktionen jedes Mal definieren, wenn Sie die Funktion aufrufen, die wie die Datei benannt ist. Normalerweise ist das nicht das, was Sie wollen, also würden Sie eine Funktion neu definieren, die wie die Datei in der Datei benannt ist.
Ich werde ein kurzes Skelett beifügen, das Ihnen eine Vorstellung davon gibt, wie das funktioniert:
# Let's again assume that these are the contents of a file called "hello".
# You may run arbitrary code in here, that will run the first time the
# function is referenced. Commonly, that is initialisation code. For example
# the `_tmux' completion function does exactly that.
echo initialising...
# You may also define additional functions in here. Note, that these
# functions are visible in global scope, so it is paramount to take
# care when you're naming these so you do not shadow existing commands or
# redefine existing functions.
hello_helper_one () {
printf 'Hello'
}
hello_helper_two () {
printf 'world.'
}
# Now you should redefine the "hello" function (which currently contains
# all the code from the file) to something that covers its actual
# functionality. After that, the two helper functions along with the core
# function will be defined and visible in global scope.
hello () {
printf '%s %s\n' "$(hello_helper_one)" "$(hello_helper_two)"
}
# Finally run the redefined function with the same arguments as the current
# run. If this is left out, the functionality implemented by the newly
# defined "hello" function is not executed upon its first call. So:
hello "$@"
Wenn Sie dieses alberne Beispiel ausführen würden, würde der erste Lauf folgendermaßen aussehen:
zsh% hallo
Initialisierung ...
Hallo Welt.
Aufeinanderfolgende Anrufe sehen dann so aus:
zsh% hallo
Hallo Welt.
Ich hoffe das klärt die Dinge auf.
(Eines der komplexeren realen Beispiele, das all diese Tricks verwendet, ist die bereits erwähnte Funktion " _tmux " aus dem funktionsbasierten Vervollständigungssystem von zsh.)