ここで `set --$args` 行は何をして、 Zsh と Bash の間で異なる動作をするのはなぜですか?

ここで `set --$args` 行は何をして、 Zsh と Bash の間で異なる動作をするのはなぜですか?

getopt設定の使用例は、Mac OSXに付属のバージョンのマンページにありますargs=$(getopt optstring $*); set -- $args。ここで何をしているのset -- $args

また、関数とテスト文字列を検討してください。

f () {
    args=$(getopt o: $*)
    set -- $args
    for i; do
        echo $i
    done
}

f -o 123 xyz

Bash 3.2および4.3では、次のものが生成されます。

-o
123
--
xyz

ただし、Zsh 5.1では次のものを生成します。

 -o 123 -- xyz

違いの原因は何ですか? Zshの別の単語分割動作のせいですか、それとも別の理由ですか?引用フラグとパラメータ拡張フラグのさまざまな組み合わせを試しましたが、実際に2つのシェルで何が起こっているのかを理解することはできません。

ベストアンサー1

これは悪いコードです。getoptほとんど利用できません。getopts組み込みシェルを使用してください(2つの利点があります。それはうまくいくこととすべてのPOSIXプラットフォームで動作することです)。

これがすることはargs=$(getopt optstring $*); set -- $args

  • 各コマンドライン引数をスペースに分割し、スペースで区切られた単語のリストに置き換えます。
  • 各結果の単語を取得し、ワイルドカードパターンとして解釈します。パターンが 1 つ以上のファイルと一致する場合は、パターンを一致するファイルのリストに置き換えます。
  • 結果の単語リストをgetoptコマンドに渡します。
  • コマンドの出力をgetopt変数に保存しますargs。これは、スペースで区切られたコマンドライン引数、オプションとその引数、オプションではなく--オペランドで順序付けられた文字列です。
  • この文字列をスペースに分割し、各単語をワイルドカードパターンとして解釈し、パターンを一致するファイルのリスト(存在する場合)に置き換えます。
  • 結果のリストを位置引数として使用します。

Bourne/POSIX スタイルのシェルでは、$foo「split+glob」演算子です。変数の値を取得するには二重引用符が必要です。"$foo"。しかし、zshでは異なる動作をします。$foonull の場合を除き、値に拡張されます。したがって、zshは位置パラメータを取得します。foofoo

Split + glob演算子の最初の使用は、次のように書くことで回避できますgetopt optstring "$@"。これにより、位置引数が正確に渡されますgetopt。ただし、出力を解析するときにスペースを使用して引数を区切るため、分割getoptは避けられません(ワイルドカードを無効にすることができます)。getopt問題は、出力があいまいであることです。パラメータのスペースと区切り文字で追加されたgetoptスペースを区別する方法はありません。getopt

これを行う正しい方法は、getopts頑丈で携帯可能です。

while getopts optstring OPTLET; do
  # We got the option -$OPTLET
  case $OPTLET in
  esac
done
shift $((OPTIND-1))
# Now the positional parameters are just the non-option operands

¹少なくともBSDバージョン。 GNUバージョンには、それを使用するための機能が追加されました。

おすすめ記事