zshでは、関数検索パス($ fpath)は一連のディレクトリを定義します。ディレクトリには、含まれる関数が初めて必要になったときに自動的にロードされるようにマークできるファイルが含まれています。
Zshには、ファイルを自動ロードする2つのモードがあります。Zshのネイティブな方法と、kshの自動ロードに似た別のモードです。後者は、KSH_AUTOLOADオプションが設定されている場合にアクティブです。Zshのネイティブモードがデフォルトであり、ここでは他の方法については説明しません(kshスタイルのオートロードの詳細については、「man zshmisc」および「man zshoptions」を参照してください)。
はい。ディレクトリ `〜/ .zfunc 'があり、それを関数検索パスの一部にしたい場合、次のようにします。
fpath=( ~/.zfunc "${fpath[@]}" )
これにより、プライベートディレクトリが検索パスの先頭に追加されます。これは、zshのインストールからの関数を独自の関数でオーバーライドする場合に重要です(たとえば、シェルの古いインストールバージョンでzshのCVSリポジトリの `_git 'などの更新された完了関数を使用する場合)。
また、「$ fpath」からのディレクトリは再帰的に検索されないことに注意してください。プライベートディレクトリを再帰的に検索する場合は、このように自分で管理する必要があります(次のスニペットでは、「EXTENDED_GLOB」オプションを設定する必要があります)。
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
訓練を受けていない人にはわかりにくいかもしれませんが、実際には「〜/ .zfunc」以下のすべてのディレクトリを「$ fpath」に追加しますが、「CVS」と呼ばれるディレクトリを無視しますzshのCVSからプライベート検索パスへの関数ツリー)。
次の行を含むファイル `〜/ .zfunc / hello 'があると仮定しましょう:
printf 'Hello world.\n'
ここで必要なのは、最初の参照時に関数が自動的にロードされるようにマークすることです。
autoload -Uz hello
「-Uzについては何ですか?」、あなたは尋ねますか?さて、それはオプションのセットに過ぎず、他のオプションが設定されていても、「autoload」は正しいことをします。関数がロードされている間、「U」はエイリアスの展開を無効にし、「KSH_AUTOLOAD」が何らかの理由で設定されていても、「z」はzshスタイルの自動ロードを強制します。
面倒を見てから、新しい「hello」関数を使用できます。
zsh%こんにちは
こんにちは世界。
これらのファイルの調達について一言:それは間違っています。その `〜/ .zfunc / hello 'ファイルを入手した場合、「Hello world」と表示されます。一度。これ以上何もない。関数は定義されません。また、必要なときにのみ関数のコードをロードするという考え方もあります。「autoload」呼び出しの後、関数の定義は読み込まれません。関数は、必要に応じて後で自動ロードされるようにマークされています。
そして最後に、$ FPATHと$ fpathに関する注意:Zshはリンクされたパラメーターとしてそれらを維持します。小文字のパラメーターは配列です。大文字バージョンは文字列スカラーで、エントリ間のコロンで結合されたリンクされた配列のエントリが含まれます。これは、配列を使用してスカラーのリストを処理する方が自然であり、スカラーパラメーターを使用するコードの下位互換性も維持するためです。$ FPATH(スカラー)を使用する場合は、注意する必要があります。
FPATH=~/.zfunc:$FPATH
動作しますが、以下は動作しません:
FPATH="~/.zfunc:$FPATH"
その理由は、チルダ展開が二重引用符内で実行されないためです。これが問題の原因である可能性があります。echo $FPATH
展開されたパスではなくチルダを出力する場合、機能しません。安全のために、次のようなチルダの代わりに$ HOMEを使用します。
FPATH="$HOME/.zfunc:$FPATH"
そうは言っても、この説明の冒頭で行ったように、配列パラメーターを使用したいです。
また、$ FPATHパラメーターをエクスポートしないでください。現在のシェルプロセスでのみ必要であり、その子では必要ありません。
更新
`$ fpath 'のファイルの内容に関して:
zshスタイルのオートロードでは、ファイルのコンテンツは定義する関数の本体です。したがって、行を含む「hello」という名前のファイルは、「hello」echo "Hello world."
という関数を完全に定義します。hello () { ... }
コードを自由に配置できますが、それは不要です
。
ただし、1つのファイルに1つの関数しか含まれないという主張は、完全に正しいわけではありません。
特に、関数ベースの補完システム(compsys)の一部の関数を見ると、それが誤解であることがすぐにわかります。関数ファイルに追加の関数を自由に定義できます。また、関数の最初の呼び出し時に必要になる可能性のある、あらゆる種類の初期化を自由に行うことができます。ただし、その場合、ファイル内のファイルのような名前の関数を常に定義し、ファイルの最後でその関数を呼び出すため、関数が最初に参照されたときに実行されます。
サブ関数を使用して、ファイル内のファイルのような名前の関数を定義しなかった場合、その関数内に関数定義(つまり、ファイル内のサブ関数の関数)が含まれることになります。ファイルのような名前の関数を呼び出すたびに、すべてのサブ関数を効果的に定義することになります。通常、それはあなたが望むものではないので、ファイル内のファイルのような名前の関数を再定義します。
短いスケルトンを含めます。これにより、どのように機能するかがわかります。
# 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 "$@"
この愚かな例を実行すると、最初の実行は次のようになります。
zsh%こんにちは
初期化しています...
こんにちは世界。
そして、連続した呼び出しは次のようになります。
zsh%こんにちは
こんにちは世界。
これで問題が解決することを願っています。
(これらのすべてのトリックを使用するより複雑な実世界の例の1つは、zshの関数ベースの補完システムですでに説明した ` _tmux '関数です。)