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では異なる動作をします。$foo
null の場合を除き、値に拡張されます。したがって、zshは位置パラメータを取得します。foo
foo
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バージョンには、それを使用するための機能が追加されました。
答え2
set -- $args
の内容に基づいて位置パラメータを設定します$args
。これでzsh
、他のPOSIXシェルとは異なる動作があります。
zsh
実装されていないフィールド分割デフォルトでは、内容である文字列を取得します$args
。bash
(および他のPOSIXシェル)と同じ動作を得るには、明示的に分割を呼び出す必要があります。
set -- ${=args}
bash
Field Splitting
contentで実行すると、$args
4つの文字列が生成されます。$#
その後、位置パラメータの数を確認できますset -- $args
。
その場合は、ワイルドカードをオフにする必要がありますbash
。set -f