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>
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.