Resposta curta: use"$@"
(observe as aspas duplas). As outras formas raramente são úteis.
"$@"
é uma sintaxe bastante estranha. É substituído por todos os parâmetros posicionais, como campos separados. Se não houver parâmetros posicionais ( $#
é 0), ele se "$@"
expande para nada (não é uma sequência vazia, mas uma lista com 0 elementos); se houver um parâmetro posicional, "$@"
é equivalente a "$1"
; se houver dois parâmetros posicionais, "$@"
é equivalente a "$1" "$2"
etc.
"$@"
permite passar os argumentos de um script ou função para outro comando. É muito útil para wrappers que fazem coisas como definir variáveis de ambiente, preparar arquivos de dados etc. antes de chamar um comando com os mesmos argumentos e opções com os quais o wrapper foi chamado.
Por exemplo, a função a seguir filtra a saída de cvs -nq update
. Além da filtragem de saída e do status de retorno (que é o de grep
e não o de cvs
), chamar cvssm
alguns argumentos se comporta como chamar cvs -nq update
com esses argumentos.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"
expande para a lista de parâmetros posicionais. Nos shells que suportam matrizes, existe uma sintaxe semelhante para expandir a lista de elementos da matriz: "${array[@]}"
(os colchetes são obrigatórios, exceto no zsh). Novamente, as aspas duplas são um pouco enganadoras: elas protegem contra a divisão de campos e a geração de padrões dos elementos da matriz, mas cada elemento da matriz termina em seu próprio campo.
Algumas conchas antigas tinham o que é indiscutivelmente um bug: quando não havia argumentos posicionais, "$@"
expandíamos para um único campo contendo uma string vazia, em vez de para nenhum campo. Isso levou à solução alternativa${1+"$@"}
(que ficou famosa através da documentação do Perl ). Somente versões mais antigas do shell Bourne real e da implementação OSF1 são afetadas, nenhuma de suas substituições compatíveis modernas (ash, ksh, bash,…) são. /bin/sh
não é afetado em nenhum sistema lançado no século XXI que eu conheça (a menos que você conte a versão de manutenção do Tru64, e mesmo que /usr/xpg4/bin/sh
seja seguro, apenas os #!/bin/sh
scripts serão afetados, e não os #!/usr/bin/env sh
scripts, desde que seu PATH esteja configurado para conformidade com POSIX) . Em resumo, esta é uma anedota histórica com a qual você não precisa se preocupar.
"$*"
sempre se expande para uma palavra. Esta palavra contém os parâmetros posicionais, concatenados com um espaço intermediário. (De maneira mais geral, o separador é o primeiro caractere do valor da IFS
variável. Se o valor de IFS
for a sequência vazia, o separador será a sequência vazia.) Se não houver parâmetros posicionais, "$*"
será a sequência vazia, se houver dois parâmetros posicionais e IFS
seu valor padrão "$*"
é equivalente a "$1 $2"
etc.
$@
e $*
aspas externas são equivalentes. Eles se expandem para a lista de parâmetros posicionais, como campos separados, como "$@"
; mas cada campo resultante é dividido em campos separados, que são tratados como padrões curinga de nome de arquivo, como de costume com expansões de variáveis não citadas.
Por exemplo, se o diretório atual contém três arquivos bar
, baz
e foo
, em seguida:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`