Развертывание параметров в $ @ не поддерживается оболочкой sh?

8

Я опубликовал ответ на вопрос об AU и обнаружил, что расширение параметра on $@не работает с shоболочкой:

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

но работает нормально bash. Это ожидаемое поведение shоболочки, и как я могу выполнить расширение там?

Кроме того, я знаю, что с -n1опцией xargsя могу передать только одну строку команде за раз, но меня интересовало, shможно ли расширить $@:

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

infile содержит:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3
αғsнιη
источник

Ответы:

12

Да, черточка здесь менее чем полезна. Хотя, строго говоря, это не вина, как ${@%...}это не указано в POSIX :

Следующие четыре разновидности расширения параметров обеспечивают обработку подстроки. [...] Если параметр равен ' #', ' *' или ' @', результат раскрытия не указан.

Странно, хотя, кажется, что если подобное расширение изменяет конец одного позиционного параметра, оно отбрасывает следующие. Но не, если это фактически не изменяет конец:

$ 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заключается в том, чтобы модифицировать один аргумент за раз:

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>
ilkkachu
источник
Sound shдумает, что $@является единственным параметром для всего файла (или будет разбит на несколько, если превысит ARG_MAX) и сделает расширение только для одного аргумента.
αғsнιη
1
Также обратите внимание, что pdksh и его производные выдают Bad substitutionошибку в этом коде. Ибо ${*%pattern}вы видите некоторые различия в поведении в таких вещах, как"$shell" -c 'printf "<%s>\n" "${*%x*}"' sh ax by
Стефан Шазелас
1
@ αғsнιη, это не так просто. обратите внимание на второй пример, где расширение оставляет позиционные параметры как отдельные слова. И я не думаю ARG_MAX, что это связано с тем, что обработка является внутренней для оболочки.
ilkkachu