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

7

Eu postei uma resposta para uma pergunta na AU, e descobri que a expansão de parâmetro em $@ não trabalhe com o sh shell:

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

mas funciona bem em bash . Esse comportamento esperado do shell sh e como posso realizar a expansão lá?

Além disso, sei que com a opção -n1 de xargs posso passar apenas uma linha para o comando por vez, mas estava interessado em saber se sh pode expandir $@ :

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

infile contém:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3
    
por αғsнιη 24.05.2018 / 12:22

1 resposta

12

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

The following four varieties of parameter expansion provide for substring processing. [...] If parameter is '#', '*', or '@', the result of the expansion is unspecified.

É estranho, parece que, se uma expansão como essa modifica o fim de um parâmetro posicional, ela elimina as seguintes. Mas não se realmente 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 "${@%...}" processando cada parâmetro posicional independentemente, o que parece ser útil.

Suponho que a solução óbvia para dash é tornar a modificação um argumento por vez:

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

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

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

Tags