web-dev-qa-db-ja.com

$ @のパラメーター展開はshシェルでサポートされていませんか?

私は 回答 をAUの質問に投稿しましたが、_$@_のパラメーター展開がshシェルでは機能しないことがわかりました。

_<infile xargs -d'\n' sh -c 'echo "${@%%/*}"' _
_

bashでは問題なく動作します。これはshシェルの予期された動作ですか、それで拡張をどのように実行できますか?

さらに、xargsの_-n1_オプションを使用すると、一度にコマンドに1行しか渡せないことを知っていますが、shが_$@_:

_<infile xargs -d'\n' -n1 sh -c 'echo "${0%%/*}"'
_

infileに含まれるもの:

_A1 /B1/C1
A 2/B2/C2
A3/B3/C3
_
8
αғsнιη

うん、ダッシュはここでは役に立たないようです。厳密に言えば、${@%...}POSIXで指定されていない であるため、厳密に言えば、これは誤りではありません。

次の4種類のパラメーター拡張は、サブストリング処理を提供します。 [...]パラメータが '#'、 '*'、または '@'の場合、展開の結果は不定です。

奇妙なことですが、そのような展開で1つの位置パラメーターの終わりを変更すると、次のパラメーターが削除されるようです。しかし、それが実際に終わりを修正しないのでなければ、そうではありません:

$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%o}";'
<fo>
$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%x}";'
<foo>
<bar>
$ dash -c 'set -- foo bar doo; printf "<%s>\n" "${@%r}";'
<foo>
<ba>

Bash、ksh、およびZshはすべて、各位置パラメータを個別に処理することで"${@#...}"および"${@%...}"を処理するように見えます。

dashの明らかな回避策は、一度に1つの引数を変更することだと思います。

for x in "$@"; do echo "${x%%/*}"; done

価値があるのは、$*で使用される接頭辞と接尾辞の削除拡張の動作もシェルによって異なることです。 Bashとkshは最初にパラメーターを変更し、その後それらを結合するようですが、Zshとdashは最初にパラメーターを結合し、連結文字列を変更します。

$ zsh -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a>
$ bash -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a b>
12
ilkkachu