Tuesday, March 8, 2011

Difference between $* and $@ in Shell



 In one of our earlier articles, we saw the different positional parameters in a shell script. We discussed about the positional parameter $*. There is one more positional parameter, $@, the definition of which is also the same as $*. Let us see in this article the exact difference between the parameters $* and $@.


 First, let us write a simple shell script to understand $@:
$ cat cmd
#!/usr/bin/bash

echo "The total no of args are: $#"
echo "The \$* is: $*"
echo "The \$@ is: $@"
On running the above program with some command line arguments:
$ ./cmd 1 2 3
The total no of args are: 3
The $* is: 1 2 3
The $@ is: 1 2 3
   As shown in the above output, both the $* and $@ behave the same. Both contain the command line arguments given.

  Let us now write a script which exactly shows the difference:
$ cat cmd
#!/usr/bin/bash

echo "Printing \$* "
for i in $*
do
        echo i is: $i
done

echo "Printing \$@ "
for i in "$@"
do
        echo i is: $i
done
Now, on running the above script:
$ ./cmd a b "c d" e
Printing $*
i is: a
i is: b
i is: c
i is: d
i is: e
Printing $@
i is: a
i is: b
i is: c d
i is: e
  In the above example, we write a for loop and display the arguments one by one using $* and $@. Notice the difference. When we pass the command line argument in double quotes("c d"), the $* does not consider them as a single entity, and splits them. However, the $@ considers them as a single entity and hence the 3rd echo statement shows "c d" together. This is the difference between $* and $@.

2 comments:

  1. I'm just a n00b, but here goes.
    I got 4 different result, depending if I quoted $* or $@ in the for loop:

    script cmd2 running:

    >cmd2 1 2 3 4 5 "6 7 8" 9
    Printing $*
    i is: 1
    i is: 2
    i is: 3
    i is: 4
    i is: 5
    i is: 6
    i is: 7
    i is: 8
    i is: 9
    Printing $@
    i is: 1
    i is: 2
    i is: 3
    i is: 4
    i is: 5
    i is: 6
    i is: 7
    i is: 8
    i is: 9
    Printing "$*"
    i is: 1 2 3 4 5 6 7 8 9
    Printing "$@"
    i is 1
    i is 2
    i is 3
    i is 4
    i is 5
    i is 6 7 8
    i is 9

    script cmd2 listing:

    #! /bin/bash

    ## No quotes $*
    echo "Printing \$* "
    for i in $*
    do
    echo i is: $i
    done

    ## No quotes $@
    echo "Printing \$@ "
    for i in $@
    do
    echo i is: $i
    done

    ## Quoted "$*"
    echo "Printing \"\$*\" "
    for i in "$*"
    do
    echo i is: $i
    done

    ## Quoted "$@"
    echo "Printing \"\$@\" "
    for i in "$@"
    do
    echo i is $i
    done

    exit

    ReplyDelete
  2. $* if quoted will always give the entire command line argument list as a single argument.

    $@, if not quoted, will behave like $*.

    ReplyDelete