Skip to content
vast-cow's blog
Go back

Understanding `$@`, `$*`, `"$@"`, and `"$*"` in Shell Scripts

Edit page

When working with shell scripts, handling command-line arguments correctly is critical. Variables like $@ and $* are commonly used to access all positional parameters—but their behavior changes significantly depending on whether they are quoted.

This subtle distinction is a frequent source of bugs. In this article, we’ll break down exactly how each form behaves, with concrete examples.


Positional Parameters: A Quick Refresher

Consider the following script invocation:

./script.sh foo bar "baz qux"

The positional parameters are:

To refer to all arguments, we use $@ or $*.


Summary Table

ExpressionMeaningBehavior
$@All argumentsWord-split into separate tokens
$*All argumentsWord-split into separate tokens
"$@"All argumentsPreserves each argument as a separate item
"$*"All argumentsJoins all arguments into a single string

$@ and $* (Unquoted)

for arg in $@; do
  echo "$arg"
done
for arg in $*; do
  echo "$arg"
done

Behavior

Without quotes, both $@ and $* behave almost identically:

Problem

./script.sh "hello world"

This will be treated as:

The original argument structure is lost, which can lead to incorrect behavior.

👉 In practice, unquoted $@ and $* are rarely appropriate.


"$@": The Safe Default

for arg in "$@"; do
  echo "$arg"
done

Behavior

Example

./script.sh foo "bar baz"

Output:

foo
bar baz

Key Properties

👉 This is the form you should use in almost all cases.


"$*": Single String Expansion

echo "$*"

Behavior

Example

./script.sh foo "bar baz"

Output:

foo bar baz

Caveats

👉 Useful primarily for logging or display purposes.


Visual Comparison

Given:

./script.sh A "B C" D
ExpressionResult
$@A B C D
$*A B C D
"$@"”A” “B C” “D”
"$*"”A B C D”

Common Pitfall

❌ Incorrect

for arg in $@; do
  cp "$arg" /dest/
done

If an argument contains spaces, it will be split incorrectly.


✅ Correct

for arg in "$@"; do
  cp "$arg" /dest/
done

This preserves each argument exactly as passed.


Practical Guidelines


Why This Difference Exists

The distinction arises from how the shell performs:

Notably, "$@" is a special case: it expands to multiple quoted strings, preserving each positional parameter individually. This behavior is unique and not shared by other expansions.


Conclusion

If you follow one rule, make it this:

Always use "$@" unless you have a specific reason not to.


Edit page
Share this post:

Comments


Previous Post
My Favorite rclone mount Settings
Next Post
(Out of order) A Tampermonkey Script That Adds a Model Settings Button to ChatGPT