Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between $* and $@

Tags:

linux

shell

unix

Who can simply explain

  1. what is the difference between $* and $@?
  2. Why there are two variables for same content as above?
like image 741
Nayana Adassuriya Avatar asked Mar 23 '14 09:03

Nayana Adassuriya


Video Answer


3 Answers

see this here :

$#    Stores the number of command-line arguments that 
      were passed to the shell program.
$?    Stores the exit value of the last command that was 
      executed.
$0    Stores the first word of the entered command (the 
      name of the shell program).
$*    Stores all the arguments that were entered on the
      command line ($1 $2 ...).
"$@"  Stores all the arguments that were entered
      on the command line, individually quoted ("$1" "$2" ...).

take an example

./command -yes -no /home/username
so now..
$# = 3
$* = -yes -no /home/username
$@ = ("-yes" "-no" "/home/username")
$0 = ./command
$1 = -yes
$2 = -no
$3 = /home/username
like image 76
ɹɐqʞɐ zoɹǝɟ Avatar answered Sep 19 '22 14:09

ɹɐqʞɐ zoɹǝɟ


Aside from the difference as described in the technical documents, it is best shown using some examples:

Lets assume we have four shell scripts, test1.sh:

#!/bin/bash
rm $*

test2.sh:

#!/bin/bash
rm "$*"

test3.sh:

#!/bin/bash
rm $@

test4.sh:

#!/bin/bash
rm "$@"

(I am using rm here instead of echo, because with echo, one can not see the difference)

We call all of them with the following commandline, in a directory which is otherwise empty:

./testX.sh "Hello World" Foo Bar

For test1.sh and test3.sh, we receive the following output:

rm: cannot remove ‘Hello’: No such file or directory
rm: cannot remove ‘World’: No such file or directory
rm: cannot remove ‘Foo’: No such file or directory
rm: cannot remove ‘Bar’: No such file or directory

This means, the arguments are taken as a whole string, joined with spaces, and then reparsed as arguments and passed to the command. This is generally not helpful when forwarding arguments to another command.

With test2.sh, we get:

rm: cannot remove ‘Hello World Foo Bar’: No such file or directory

So we have the same as for test{1,3}.sh, but this time, the result is passed as one argument.

test4.sh has something new:

rm: cannot remove ‘Hello World’: No such file or directory
rm: cannot remove ‘Foo’: No such file or directory
rm: cannot remove ‘Bar’: No such file or directory

This implies that the arguments are passed in a manner equivalent to how they were passed to the the script. This is helpful when passing arguments to other commands.

The difference is subtle, but will bite you when passing arguments to commands which expect information at certain points in the command line and when spaces take part in the game. This is in fact a good example of one of the many pitfalls of most shells.

like image 35
Jonas Schäfer Avatar answered Sep 22 '22 14:09

Jonas Schäfer


There is no difference if you do not put $* or $@ in quotes. But if you put them inside quotes (which you should, as a general good practice), then $@ will pass your parameters as separate parameters, whereas $* will just pass all params as a single parameter.

Take these scripts (foo.sh and bar.sh) for testing:

>> cat bar.sh
echo "Arg 1: $1"
echo "Arg 2: $2"
echo "Arg 3: $3"
echo

>> cat foo.sh
echo '$* without quotes:'
./bar.sh $*

echo '$@ without quotes:'
./bar.sh $@

echo '$* with quotes:'
./bar.sh "$*"

echo '$@ with quotes:'
./bar.sh "$@"

Now this example should make everything clear:

>> ./foo.sh arg1 "arg21 arg22" arg3
$* without quotes:
Arg 1: arg1
Arg 2: arg21
Arg 3: arg22

$@ without quotes:
Arg 1: arg1
Arg 2: arg21
Arg 3: arg22

$* with quotes:
Arg 1: arg1 arg21 arg22 arg3
Arg 2:
Arg 3:

$@ with quotes:
Arg 1: arg1
Arg 2: arg21 arg22
Arg 3: arg3

Clearly, "$@" gives the behaviour that we generally want.


More detailed description:

Case 1: No quotes around $* and $@:

Both have same behaviour.

./bar.sh $* => bar.sh gets arg1, arg2 and arg3 as separate arguments

./bar.sh $@ => bar.sh gets arg1, arg2 and arg3 as separate arguments

Case 2: You use quotes around $* and $@:

./bar.sh "$*" => bar.sh gets arg1 arg2 arg3 as a single argument

./bar.sh "$@" => bar.sh gets arg1, arg2 and arg3 as a separate arguments

More importantly, $* also ignores quotes in your argument list. For example, if you had supplied ./foo.sh arg1 "arg2 arg3", even then:

./bar.sh "$*" => bar.sh will still receive arg2 and arg3 as separate parameters!

./bar.sh "$@" => will pass arg2 arg3 as a single parameter (which is what you usually want).

Notice again that this difference occurs only if you put $* and $@ in quotes. Otherwise they have the same behaviour.

Official documentation: http://www.gnu.org/software/bash/manual/bash.html#Special-Parameters

like image 38
Hari Menon Avatar answered Sep 19 '22 14:09

Hari Menon