Para a terceira versão, você deseja "$*"
não "$@"
.
Explicação
Para ilustrar, vamos definir alguns argumentos posicionais:
$ set -- arg1 arg2 arg3
Agora, vamos lê-los com sua formulação echo
:
$ printf "%s\n" "$(echo $@)"
arg1 arg2 arg3
Vamos ver o que o "$@"
faz com eles:
$ printf "%s\n" "$@"
arg1
arg2
arg3
A diferença é que "$@"
se expande para três palavras, enquanto "$(echo $@)"
se expande para uma única string. Se você quiser um comportamento como "$(echo $@)"
, use "$*"
:
$ printf "%s\n" "$*"
arg1 arg2 arg3
Documentação
De man bash
:
"$*"
produz uma única string:
"$*" is equivalent to "$1c$2c...", where c is the first character of the value of the IFS variable.
Por contraste, man bash
afirma que $@
produz uma série de palavras:
"$@" is equivalent to "$1" "$2" ...
Usando o eval
Observe:
$ echo 'printf "%s\n" "' "$@" '"'
printf "%s\n" " arg1 arg2 arg3 "
Quando o bash avalia o comando echo
, "$@"
expande para separar palavras. echo
, no entanto, pega essas palavras separadas e as combina em uma string. Nós vimos isso antes quando olhamos para "$(echo $@)"
. eval
funciona de maneira semelhante. Faz uma string fora de todos os seus argumentos e avalia essa string. Assim:
$ eval 'printf "%s\n" "' "$@" '"'
arg1 arg2 arg3
Isso também é documentado por man bash
:
eval [arg ...]
The args are read and concatenated together into a single command. This command is then read and executed by the shell, ...