¿Cuál es la diferencia entre $@ y $*

¿Cuál es la diferencia entre $@ y $*

De acuerdo aesta página, $@ y $* hacen prácticamente lo mismo:

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

Después de buscar todos los resultados principales en Google, no puedo encontrar ninguna explicación de por qué habría 2 sintaxis aparentemente duplicadas.

Parecen funcionar igual en mis 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. ¿Se prefiere uno sobre el otro?
  2. ¿Por qué hay 2 variables integradas para hacer exactamente lo mismo?

Fuentes adicionales
bash.cyberciti.biz

Respuesta1

No son lo mismo. $*es una sola cadena, mientras que $@es una matriz real. Para ver la diferencia, ejecute el siguiente script así:

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

La secuencia de comandos:

#!/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              

La explicación y los resultados de los cuatro casos se encuentran a continuación.

En el primer caso, los parámetros se consideran como un largocitadocadena:

Using "$*":
one two three four

Caso 2 (sin comillas): el bucle divide la cadena en palabras for:

Using $*:
one
two
three
four

Caso 3: trata cada elemento de $@ como una cadena entre comillas:

Using "$@":
one
two
three four

Último caso: trata cada elemento como una cadena sin comillas, por lo que el último se divide nuevamente por lo que equivale a for three four:

Using $@:
one
two
three
four

Respuesta2

La diferencia viene en cómo se expanden.

$*se expande a un solo argumento con todos los elementos delimitados por espacios (en realidad, el primer carácter de $IFS).
$@se expande a múltiples argumentos.

Por ejemplo

#!/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>

Respuesta3

puedes revisarGuía para principiantes de Bashpara más información. Estos hacen prácticamente lo mismo con la diferencia de cómo está separado:

$*- Se expande a los parámetros posicionales, comenzando desde uno. Cuando la expansión ocurre entre comillas dobles, se expande a una sola palabra con el valor de cada parámetro separado por el primer carácter de la variable especial IFS.

$@- Se expande a los parámetros posicionales, comenzando desde uno. Cuando la expansión se produce entre comillas dobles, cada parámetro se expande a una palabra separada.

Pero a menos que establezca IFSun valor distinto al predeterminado, podría verse idéntico.

Respuesta4

¿Se prefiere uno sobre el otro?

Una respuesta corta es "$@".

Si los usas sin comillas dobles, son iguales. En este caso no hay nadie preferido sobre otro. Pero te sugiero que los uses siempre entre comillas dobles, excepto que sepas exactamente lo que quieres.

¿Por qué hay 2 variables integradas para hacer exactamente lo mismo?

No hay diferencia entre $*y $@, pero "$@"y "$*"tienen.

Puedes ver mi respuesta enesta publicaciónpara ver en qué se diferencian.

información relacionada