Quando não são citados, $* e $@ são iguais. Você não deve usar nenhum desses, porque eles podem quebrar inesperadamente assim que você tiver argumentos contendo espaços ou curingas.
"$*" expande para uma única palavra "$1c$2c..." . Geralmente c é um espaço, mas na verdade é o primeiro caractere de IFS , então pode ser qualquer coisa que você escolher.
O único bom uso que encontrei para ele é:
associa argumentos com vírgula (versão simples)
join1() {
IFS=,
echo "$*"
}
join1 a b c # => a,b,c
associa argumentos com o delimitador especificado (versão melhorada)
join2() {
typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
shift
echo "$*"
}
join2 + a b c # => a+b+c
"$@" se expande para separar palavras: "$1" "$2" ...
Isso é quase sempre o que você quer. Ele expande cada parâmetro posicional para uma palavra separada, o que o torna perfeito para usar argumentos de linha de comando ou de função e depois passá-los para outro comando ou função. E porque ele se expande usando aspas duplas, isso significa que as coisas não quebram se, digamos, "$1" contiver um espaço ou um asterisco ( * ).
Vamos escrever um script chamado svim que executa vim com sudo . Vamos fazer três versões para ilustrar a diferença.
svim1
#!/bin/sh
sudo vim $*
svim2
#!/bin/sh
sudo vim "$*"
svim3
#!/bin/sh
sudo vim "$@"
Todos estarão bem para casos simples, por ex. um único nome de arquivo que não contém espaços:
svim1 foo.txt # == sudo vim foo.txt
svim2 foo.txt # == sudo vim "foo.txt"
svim2 foo.txt # == sudo vim "foo.txt"
Mas apenas $* e "$@" funcionam corretamente se você tiver vários argumentos.
svim1 foo.txt bar.txt # == sudo vim foo.txt bar.txt
svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"
E somente "$*" e "$@" funcionarão corretamente se você tiver argumentos contendo espaços.
svim1 "shopping list.txt" # == sudo vim shopping list.txt # two file names!
svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
svim3 "shopping list.txt" # == sudo vim "shopping list.txt"
Portanto, apenas "$@" funcionará corretamente o tempo todo.
typeset é como criar uma variável local em ksh ( bash e ash use local ). Isso significa que IFS será restaurado para seu valor anterior quando a função retornar. Isso é importante, porque os comandos executados posteriormente podem não funcionar corretamente se IFS estiver definido como algo fora do padrão.