Adicione set -v
à sua função e você verá o que está acontecendo:
$ f (){ set -v; sudo -- sh -c "cd /tmp; echo \"$@\""; }
$ f 1 2
+ sudo -- sh -c 'cd /tmp; echo "1' '2"'
O que está acontecendo? Seu uso de $@
criou duas cadeias que foram citadas como " cd /tmp; echo "1
" e 2"
. Você pode usar $*
se não quiser essa divisão. Veja a seção da página man bash em Parâmetros Especiais :
@ ... When the expansion occurs within double quotes, each parameter expands to a separate word. ... If ... within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word.
Portanto, no seu caso, a única string (ou palavra) "xxx $ @ yyy" se expande para 2 strings 'xxx1' e '2yyy'. Você pode testar isso usando set -- 1 2 3
para definir $@
e, em seguida, usar printf ">%s<" "$@"
para ver o número de palavras que "$@"
se torna (como o printf repetirá o formato de cada argumento):
$ set -- 1 2 3
$ printf ">%s< " "x$@y"
>x1< >2< >3y<
$ printf ">%s< " "x$*y"
>x1 2 3y<
Se você quiser passar argumentos para sh -c command
um hack é colocá-los após o único comando como argumentos, mas isso pode não funcionar em todos os shells:
f (){ set -v; sudo -- sh -c 'cd /tmp; echo "$@"' sh "$@"; }
f 1 2
+ sudo -- sh -c 'cd /tmp; echo "$@"' sh 1 2
O argumento sh
extra é porque o primeiro argumento é tomado pelo shell como o nome do processo.