Qual é a diferença entre $@ e $*

Qual é a diferença entre $@ e $*

De acordo comesta página, $@ e $* fazem praticamente a mesma coisa:

The $@ holds list of all arguments passed to the script. 
The $* holds list of all arguments passed to the script.

Depois de pesquisar todos os principais resultados no Google, não consigo encontrar nenhuma explicação de por que haveria duas sintaxes aparentemente duplicadas.

Eles parecem funcionar da mesma forma em meus scripts.

cat foo.sh
#!/bin/bash
echo The parameters passed in are $@
echo The parameters passed in are $*

./foo.sh herp derp
The parameters passed in are herp derp
The parameters passed in are herp derp
  1. Um é preferido ao outro?
  2. Por que existem 2 variáveis ​​internas para fazer exatamente a mesma coisa?

Fontes adicionais
bash.cyberciti.biz

Responder1

Eles não são iguais. $*é uma única string, enquanto $@é uma matriz real. Para ver a diferença, execute o seguinte script assim:

 > ./test.sh one two "three four"

O roteiro:

#!/bin/bash

echo "Using \"\$*\":"
for a in "$*"; do
    echo $a;
done

echo -e "\nUsing \$*:"
for a in $*; do
    echo $a;
done

echo -e "\nUsing \"\$@\":"
for a in "$@"; do
    echo $a;
done

echo -e "\nUsing \$@:"
for a in $@; do
    echo $a;
done              

A explicação e os resultados para os quatro casos estão abaixo.

No primeiro caso, os parâmetros são considerados como um longocitadocorda:

Using "$*":
one two three four

Caso 2 (sem aspas) - a string é dividida em palavras pelo forloop:

Using $*:
one
two
three
four

Caso 3 - trata cada elemento de $@ como uma string entre aspas:

Using "$@":
one
two
three four

Último caso - trata cada elemento como uma string sem aspas, então o último é novamente dividido pelo valor for three four:

Using $@:
one
two
three
four

Responder2

A diferença está em como eles são expandidos.

$*expande para um único argumento com todos os elementos delimitados por espaços (na verdade, o primeiro caractere de $IFS).
$@se expande para vários argumentos.

Por exemplo

#!/bin/bash
echo "With *:"
for arg in "$*"; do echo "<$arg>"; done
echo
echo "With @:"
for arg in "$@"; do echo "<$arg>"; done

 

$ /tmp/test.sh 1  2 "3  4"
With *:
<1 2 3  4>

With @:
<1>
<2>
<3  4>

Responder3

Você pode revisarGuia para iniciantes do BashPara maiores informações. Eles fazem praticamente a mesma coisa, com a diferença de como são separados:

$*- Expande para os parâmetros posicionais, começando em um. Quando a expansão ocorre entre aspas duplas, ela se expande para uma única palavra com o valor de cada parâmetro separado pelo primeiro caractere da variável especial IFS.

$@- Expande para os parâmetros posicionais, começando em um. Quando a expansão ocorre entre aspas duplas, cada parâmetro se expande para uma palavra separada.

Mas, a menos que você defina IFSum valor diferente do padrão, ele poderá parecer idêntico.

Responder4

Um é preferido ao outro?

Uma resposta curta é "$@".

Se você usá-los sem aspas duplas, eles serão iguais. Não há ninguém preferido sobre o outro neste caso. Mas eu sugiro que você sempre os use com aspas duplas, a menos que você saiba exatamente o que deseja.

Por que existem 2 variáveis ​​internas para fazer exatamente a mesma coisa?

Não há diferença entre $*e $@, mas "$@"e "$*"tem.

Você pode ver minha resposta emesta postagempara ver como eles são diferentes.

informação relacionada