関数を含む環境変数はbashハックです。Zshには類似したものはありません。数行のコードで同様のことができます。環境変数には文字列が含まれています。Shellshockが発見される前のbashの古いバージョンは、関数のコードを変数に保存し、その変数の名前は関数の名前で、値の() {
後に関数のコードが続き、その後に}
。次のコードを使用して、このエンコードで変数をインポートし、bashのような設定で変数を実行することができます。zshはすべてのbash機能をエミュレートできるわけではないことに注意してください。できることは少し近くなることです(たとえば$foo
、値を分割してワイルドカードを展開し、配列を0ベースにする)。
bash_function_preamble='
emulate -LR ksh
'
for name in ${(k)parameters}; do
[[ "-$parameters[name]-" = *-export-* ]] || continue
[[ ${(P)name} = '() {'*'}' ]] || continue
((! $+builtins[$name])) || continue
functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done
(Shellshockの最初の発見者であるStéphaneChazelasが指摘したように、この回答の以前のバージョンは、関数定義の形式が正しくない場合、この時点で任意のコードを実行できます。このバージョンは、もちろん、コマンドを実行すると環境からインポートされた関数である可能性があります。)
シェルショック後バージョンのbashは、無効な変数名(例:)を使用して環境内の関数をエンコードしますBASH_FUNC_myfunc%%
。これにより、zshは環境からそのような変数名を抽出するためのインターフェースを提供しないため、信頼性の高い解析が困難になります。
これはお勧めしません。スクリプトでエクスポートされた関数に依存することは、悪い考えです。スクリプトに目に見えない依存関係が作成されます。機能を持たない環境(シェル初期化ファイルを変更した後、別のマシン、cronジョブなど)でスクリプトを実行すると、スクリプトは機能しなくなります。代わりに、すべての関数を1つ以上の個別のファイル(など~/lib/shell/foo.sh
)に保存し、使用する関数をインポートしてスクリプトを開始します(. ~/lib/shell/foo.sh
)。このようにして、を変更するとfoo.sh
、どのスクリプトがそれに依存しているかを簡単に検索できます。スクリプトをコピーすると、必要な補助ファイルを簡単に見つけることができます。
Zsh(およびその前のksh)は、使用されるスクリプトに関数を自動的にロードする方法を提供することにより、これをより便利にします。制約は、ファイルごとに1つの関数しか配置できないことです。関数をオートロードとして宣言し、関数の名前が関数の名前であるファイルに関数定義を配置します。このファイルをリストされているディレクトリに$fpath
配置します(FPATH
環境変数を使用して設定できます)。スクリプトで、でオートロードされた関数を宣言しautoload -U foo
ます。
さらに、zshはスクリプトをコンパイルして、解析時間を節約できます。zcompile
スクリプトをコンパイルするために呼び出します。これにより、拡張子を持つファイルが作成されます.zwc
。このファイルが存在autoload
する場合、ソースコードの代わりにコンパイル済みファイルがロードされます。このzrecompile
関数を使用して、ディレクトリ内のすべての関数定義を(再)コンパイルできます。