G

Command-Line Arguments in Shell Scripts

There are a few ways to loop over command-line arguments in shell scripts. There’s $* and $@, and then there are quoted ("$* and "$@") versions of each. Each one behaves differently, but there’s one that you almost always want to use.

Here’s a shell script named demo.sh that will illustrate the difference:

#!/bin/sh

for argument in $*; do
  echo "$argument"
done

(For each bit about $* vs $@ vs "$*" vs "$@", assume I changed the $* part of the script accordingly.)

Unquoted $*

Unquoted $* will ignore quotes in arguments:

# $*
$ ./demo.sh "keep it together" two
keep
it
together
two

This behaves exactly like ./demo.sh keep it together two. We want it to print out keep it together and two as separate lines, so this is wrong.

Unquoted $@

Now let’s try with $@:

# $@
$ ./demo.sh "keep it together" two
keep
it
together
two

Unquoted $@ acts exactly like unquoted $*.

Quoted "$*"

Now let’s try it with "$*":

# "$*"
$ ./demo.sh "keep it together" two
keep it together two

As you can see, it combined the two arguments into one long argument

Technically, it’s joining the two arguments with the $IFS (or “internal field separator”) variable. By default, "$IFS" is three characters: a space, a tab, and a newline. "$*" only joins with the first character of $IFS, so it print the arguments with a space between them, but we can temporarily change it:

#!/bin/sh

IFS="GABE"
for argument in "$*"; do
  echo "$argument"
done
$ ./demo.sh "keep it together" two
keep it togetherGtwo

In any case, it’s still not quite there, so let’s keep looking.

Quoted "$@"

And finally, the one that we always want to use, "$@":

# "$@"
$ ./demo.sh "keep it together" two
keep it together
two

At last, we have printed two lines for two arguments, appropriately split up according to how we passed them in as arguments.