
(この質問では Maccaffeinate
ツールを例として使用していますが、この概念は、xargs
引数としてユーティリティを受け入れるすべてのツール (つまり ) に適用されます。)
Mac のcaffeinate
ツールは、ユーティリティの名前 ( ) を受け入れますcaffeinate sleep 1
(ここでsleep
はユーティリティ)。zsh
ツール自体を変更せずに、関数も受け入れる方法はありますか? たとえば、次のようになります。
function mysleep {
sleep 2
}
caffeinate mysleep # mysleep: No such file or directory
編集: この質問は確かに Bash の重複です。回答を教えてくれてありがとう。ただし、zshexport -f
では機能しません。zsh でこれを行う方法はありますか? (混乱を減らすためにタグを削除していますbash
。)
答え1
caffeinate
新しいプロセスでコマンドを実行することを期待します。
関数を解釈するにはzsh
、zsh
コマンドが必要です。
そして、その関数の定義(および必要になる可能性のある他の関数)を渡す必要があります。たとえば、次のようになります。
mysleep() {
sleep 2
}
caffeinate zsh -c "$(functions mysleep);mysleep"
functions mysleep
関数を呼び出す前に解釈のためにmysleep
new に渡す関数の定義をダンプします。そのため、呼び出された関数は次のように解釈することになります。zsh
zsh
caffeinate
mysleep() {
sleep 2
};mysleep
と比較するとbash
:
mysleep() {
sleep 2
}
export -f mysleep
caffeinate bash -c "mysleep"
(入力する文字数が 2 文字短くなります) はbash
次のようになります。
execve("/path/to/caffeinate",
["caffeinate", "bash", "-c", "mysleep"],
["BASH_FUNC_mysleep%%=() { sleep 2\n}", rest-of-environment])
一方zsh
、 の場合は次のようになります。
execve("/path/to/caffeinate",
["caffeinate", "zsh", "-c", "mysleep () {\n\tsleep 2\n};mysleep"],
[rest-of-environment])
後者のアプローチにはいくつかの利点があると思います。
- 完全な制御権があります。関数定義をどのように渡し、どのように使用するかがわかっています。ここでの shellshock のような厄介な事態が発生する余地は少なくなります。
- 関数定義を保持する bash 環境変数の名前に
%
文字が含まれているため (含まれていなくても、sudo
たとえば を考えてみてください)、caffeinate
それが実行されるコマンドに伝播されるかどうかは保証されませんbash
。 - 伝播する場合、関数定義はargv[]ではなくenvp[]に格納されるため、その環境で実行される他のすべてのコマンドの環境を汚染することになります(
sleep
この例の場合も含みます)。 - (マイナー) シェル コードは短くなりますが
bash
、渡されるデータが増えるためexecve()
、そのシステム コールの E2BIG 制限に大きく影響します。
環境を使用したい場合は、次のようにすることもできます。
FUNCS=$(functions mysleep) caffeinate zsh -c '
eval "$FUNCS";mysleep'
ここでの場合、関数の実行中に を実行するだけでcaffeinate
よく、必ずしも関数を実行する必要はありません。次のような他のアプローチを使用できます。caffeinate
mysleep | caffeinate cat
cat
実行される限り実行されますmysleep
。mysleep
ただし、別のプロセスで実行され、標準出力に影響しますmysleep
。
mysleep 3> {fd}>(caffeinate cat)
両方の問題を解決します。
mysleep
上記のように、との間にパイプが作成されますcat
。ただし、パイプの書き込み側は、 に格納されている 10 を超える新しく割り当てられたファイル記述子上にあり、$fd
通常mysleep
は書き込まれません。したがって、 は何も読み取らず、パイプのファイルの終わりまで待機します。これは、 (およびその fd を継承するすべての子プロセス)が終了したcat
場合にのみ発生します。mysleep
答え2
これを行う最善の方法は、関数をスクリプト ファイルに配置し、次のようにスクリプトを呼び出すことです。
caffeinate myfunction.sh
myfunction.sh の内容:
#!/bin/bash
sleep 2
スクリプト ファイルが実行可能であることを確認してください。そうでない場合は、権限エラーが発生します。
chmod +x myfunction.sh