zshで独自のシェル関数を定義してロードする方法

zshで独自のシェル関数を定義してロードする方法

zshで独自のシェル機能を定義して実行するのに問題があります。フォローする説明する公式ドキュメントで最初に簡単な例を試してみましたが、うまくいきませんでした。

フォルダがあります。

~/.my_zsh_functions

functions_1このフォルダには「With User Permissions」というファイルがありますrwx。このファイルでは、次のシェル関数を定義します。

my_function () {
echo "Hello world";
}

FPATHインクルードフォルダのパスを定義しました~/.my_zsh_functions

export FPATH=~/.my_zsh_functions:$FPATH

以下を使用して、フォルダが関数パス.my_zsh_functionsにあることを確認できます。echo $FPATHecho $fpath

しかし、シェルで次のことを試した場合:

> autoload my_function
> my_function

私は得る:

zsh: my_test_function: 関数定義ファイルが見つかりません。

電話をかけるには別の措置を講じる必要がありますかmy_function

修正する:

これまでの答えは、zsh機能を使用してファイルを取得することを示唆しています。これは言葉ですが、少し混乱しています。 zshはこれらのファイルがどこにあるかを知る必要はありませんかFPATH?目的は何ですかautoload

答え1

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[@]}"
)

訓練されていない人の目には秘密に見えるかもしれませんが、実際には「CVS」という名前のディレクトリを無視しながら、 `~/.zfunc'の下のすべてのディレクトリを `$ fpath'に追加します(ディレクトリ全体を確認したい場合に便利です。 )。 zshのCVSからプライベート検索パスに関数ツリーを追加するには)

次の行を含む「~/.zfunc/hello」ファイルがあるとします。

printf 'Hello world.\n'

今あなたがしなければならないことは表示初めて参照したときに自動的にロードされる関数:

autoload -Uz hello

「-Uzとはどういう意味ですか?」と尋ねることもできます。どのオプションが設定されているかにかかわらず、自動ロードが正しい操作を実行できるようにするオプションのセットです。 「U」は関数のロード時にエイリアス拡張を無効にし、「z」は何らかの理由で「KSH_AUTOLOAD」が設定されていても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」というファイルには、echo "Hello world."「hello」という関数を完全に定義する行が含まれています。hello () { ... }必要に応じてコードを変更できますが、これは重複しています。

しかし、ファイルに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つは、すでに述べた `_tmux' zshの関数ベースの完成システムの関数です。 )

答え2

要素によって指定されたディレクトリのファイル名は、fpathその要素が定義する自動ロード機能の名前と一致する必要があります。

関数に名前が付けmy_functionられ、~/.my_zsh_functions予想されるディレクトリにあるため、fpath定義はmy_functionそのファイルに存在する必要があります~/.my_zsh_functions/my_function

提案されたファイル名の複数形()は、functions_1ファイルに複数の機能を配置する予定であることを示します。これは自動ローディングが機能する方法ではありませんfpath。各ファイルには関数定義が必要です。

答え3

あなたが望むのは初期化が遅れる機能なので、購入は確かに正しいアプローチではありません。それがautoload目的です。目標を達成する方法は次のとおりです。

あなたはecho "hello world"という関数を~/.my_zsh_functions入れたいと言いましたmy_function。しかし、関数呼び出しでラップしますが、これはうまくいきません。~/.my_zsh_functions/my_function代わりに、echo "Hello world"関数ラッパーではないという関数を作成する必要があります。包装紙を本当に好むなら、そうすることもできます。

# ~/.my_zsh_functions/my_function
__my_function () {
    echo "Hello world";
}
# you have to call __my_function
# if this is how you choose to do it
__my_function

次に、ファイル.zshrcに以下を追加します。

fpath=(~/.my_zsh_functions $fpath);
autoload -U ~/.my_zsh_functions/my_function

新しいZSHシェルをロードするときに入力しますwhich my_function。以下が表示されます。

my_function () {
    # undefined
    builtin autoload -XU
}

ZSHはちょうどmy_functionを削除しましたautoload -X。今my_functionすぐ入力して実行してくださいmy_function。印刷物を表示する必要があり、Hello world実行すると、which my_function次のように関数がいっぱいになることがわかります。

my_function () {
    echo "Hello world"
}

今、フォルダ~/.my_zsh_functions全体がautoload.zshrc

# add ~/.my_zsh_functions to fpath, and then lazy autoload
# every file in there as a function
fpath=(~/.my_zsh_functions $fpath);
autoload -U $fpath[1]/*(.:t)

答え4

次のように、$ZDOTDIR/.zshrcのすべての機能を含むファイルを「ロード」できます。

source $ZDOTDIR/functions_file

あるいは、「source」の代わりにドット「.」を使用することもできます。

関連情報