A expansão de parâmetros em $ @ não é suportada pelo shell sh?

8

Postei uma resposta para uma pergunta na AU e descobri que a expansão de parâmetros no $@não funciona com o shshell:

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

mas funciona bem bash. Esse comportamento é esperado do shshell e como posso executar a expansão lá?

Além disso, eu sei que, com a -n1opção de xargs, posso passar apenas uma linha para o comando por vez, mas estava interessado em saber se é shpossível expandir $@:

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

infile contém:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3
αғsнιη
fonte

Respostas:

12

Sim, o traço parece ser menos útil aqui. Embora não seja culpa, estritamente falando, como não${@%...} é especificado pelo POSIX :

As quatro variedades a seguir de expansão de parâmetros fornecem processamento de substring. [...] Se o parâmetro for ' #', ' *' ou ' @', o resultado da expansão não é especificado.

É estranho, porém, parece que, se uma expansão como essa modifica o final de um parâmetro posicional, ele descarta os seguintes. Mas não se ele não modificar o final:

$ 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 e Zsh parecem manipular "${@#...}"e "${@%...}"processar cada parâmetro posicional de forma independente, o que parece útil.

Suponho que a solução óbvia para isso dashé fazer a modificação um argumento de cada vez:

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

Pelo que vale, o comportamento das expansões de remoção de prefixo / sufixo usadas $*também varia entre shells. Bash e ksh parecem modificar os parâmetros primeiro e juntá-los a eles depois, enquanto Zsh e dash juntam os parâmetros primeiro e modificam a sequência concatenada:

$ zsh -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a>
$ bash -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a b>
ilkkachu
fonte
sons shpensa $@é um único parâmetro para o arquivo inteiro (ou vai quebrar a múltiplos se exceder ARG_MAX) e fazer a expansão no único argumento.
αғsнιη 24/05
1
Observe também que pdksh e derivados fornecem um Bad substitutionerro nesse código. Pois ${*%pattern}, você vê alguma variação no comportamento em coisas como"$shell" -c 'printf "<%s>\n" "${*%x*}"' sh ax by
Stéphane Chazelas
1
@ αғsнιη, não é assim tão simples. observe o segundo exemplo em que a expansão deixa os parâmetros posicionais como palavras separadas. E eu não acho que ARG_MAXentra, esse processamento é interno ao shell.
Ilkkachu