Bash変数を「拡張」する方法(埋め込みコードはbashでは機能しますがzshでは機能しません)

Bash変数を「拡張」する方法(埋め込みコードはbashでは機能しますがzshでは機能しません)

次の答えこれパスを制御する方法の優れた説明みんなコマンドの変数。

パラメータごとにこれを行う方法を学びたいです。観察(これはでテストされましたzsh):

$ program() { echo 1: $1 2: $2 3: $3; }

$ run() { program "$@"; }

$ run2() { echo `run $1`; }

$ run2 'a b' c
1: a b 2: 3:

$@スペースを含む文字列である最初の引数を渡し、そのスプライススタイルを別のコマンドに渡す方法を望みます。たとえば、run2 "a b" c生産する必要があります1: a 2: b 3:

この時点で私はすぐに問題を解決しました。これは、私のテストコードがzshでテストされたときに中断されても、実際のbashスクリプトで実装された後に機能するためです。

これは、「安全でない」文字列とパラメータ処理の複雑さに依存する可能性があることを示唆しています。したがって、これはこの動作を確実に実装するより強力な方法についての意見を求めることです。

ベストアンサー1

bashとzshの重要な違いは、run2呼び出し方法run、特に引用符を使用しない場合の効果です$1

  • zshでは、run $1「空の場合は削除」演算子が適用されます$1。つまり、run最初の引数がに渡されて呼び出されたときに引数なしで呼び出される場合、空の場合(または最初のrun2引数run2run2run
  • 他のBourneスタイルのシェル(bashなど)では、run $1「split + glob」演算子が適用されます$1。つまり、最初の引数をrun2スペースで区切られたチャンクに分割し、1、各部分をワイルドカードパターン2として解釈し、それを各ワイルドカードパターンまたは複数に置き換えます。一致は、一致するリストでより多くのファイルを表示します。

したがって、zshでは引数とともに呼び出されますがrun2 'a b' c(引数はそのまま渡されます)、bashでは2つの引数(スペースで区切られた部分に分割)で呼び出されます。runa brunab

$@スペースを含む文字列である最初の引数を渡し、そのスプライススタイルを別のコマンドに渡す方法を望みます。たとえば、run2 "a b" c生産する必要があります1: a 2: b 3:

あなたの説明とあなたの例は異なることを言います。最初のパラメータを別のコマンドに渡すには、パラメータが分割されていないことをrun "$1"確認してください。パラメータを変更せずに渡すのはです"$@"

あなたが本当に欲しいのは、最初の引数をrun2スペースで区切られた塊に分割するようです。 Bashでは、IFSワイルドカード拡張をオフにしてから(デフォルトが変更されていないと仮定して)、引用符を付けない拡張を使用してこれを達成できます。

run2 () ( set -f; run $1; )

echo "$(somecommand)"本質的にサブシェルで実行するのと同じです。コマンド出力に分割+globを適用するのではなく、somecommandこれが意味するバイなので、重複したecho-command-substitutionを削除しました。)echo $(somecommand)

zshでは、=パラメータ置換に文字を使用して値のグローバル分割を実行できます(グロビングなし)。

run2 () { run $=1; }

zshの構文は、通常のshの構文と互換性がありません。 zshからshスクリプトを取得するには、次のemulateビルドを使用できます。

emulate sh -c '. myscript.sh'

emulate kshkshの特定の機能をシミュレートするために使用されます。これはすべてのbash機能をエミュレートするわけではありませんが、配列を使用できるようにします。

1もっと一般的にはIFS
²この機能がオフになっていない場合set -f

おすすめ記事