(この質問ではMaccaffeinate
ツールを例として使用していますが、この概念はxargs
ユーティリティを引数として受け入れるすべてのツールに適用されます。)
Mac用のツールではcaffeinate
ユーティリティ名を受け入れます(caffeinate sleep 1
たとえば、sleep
ユーティリティはどこにあります)。zsh
ツール自体を変更せずに機能を許可する方法はありますか?たとえば、
function mysleep {
sleep 2
}
caffeinate mysleep # mysleep: No such file or directory
編集:この質問は実際にBashと重複しています。答えを教えてくれてありがとう。しかし、zshではexport -f
動作しません。 zshでこれを行う方法はありますか? (bash
混雑を減らすためにラベルを削除しています。)
答え1
caffeinate
コマンドが新しいプロセスで実行されることを期待します。
機能を解釈するにはコマンドがzsh
必要ですzsh
。
関数定義(および必要な他の関数)を渡す必要があります。たとえば、次のようになります。
mysleep() {
sleep 2
}
caffeinate zsh -c "$(functions mysleep);mysleep"
functions mysleep
byが最終的に解釈されるように関数を呼び出す前に、解釈のために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])
後者のアプローチにはいくつかの利点があります。
- 私たちは完全な制御権を持っています。関数定義を渡す方法とそれを使用する方法を知っています。ここでは、シェルショックのような不快なことが発生する可能性が少なくなります。
- 関数定義を渡す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
。ただし、パイプの書き込み端は$fd
10より大きい新しく割り当てられたファイル記述子(に格納されています)にあり、mysleep
通常は記録されません。cat
したがって、何も読みませんが、パイプのファイルが終了するのを待ちます。これはmysleep
(およびこのfdを継承するすべての子プロセス)が終了した場合にのみ発生します。
答え2
これを行う最善の方法は、関数をスクリプトファイルに入れて、次のようにスクリプトを呼び出すことです。
caffeinate myfunction.sh
myfunction.shの内容:
#!/bin/bash
sleep 2
スクリプトファイルが実行可能であることを確認してください。それ以外の場合、権限エラーが発生します。
chmod +x myfunction.sh