Skip to content
Latchkey

Shell "$@" vs "$*" quoting mistakes in CI

Only "$@" forwards positional parameters as separate, intact words. "$*" joins them into one string (separated by the first $IFS character), and unquoted $@/$* both word-split and glob. A wrapper script that forwards arguments the wrong way corrupts any argument containing spaces or glob characters.

What this error means

A wrapper or entrypoint script passes arguments to an inner command, but an argument with a space arrives split in two, or all arguments arrive fused into one. Works for simple args, breaks on paths with spaces.

bash
# passing a single arg "my file.txt"
run "$*"     # inner command sees one arg: "my file.txt other"
run $@       # inner command sees: my  file.txt  (split on space)
run "$@"     # correct: each original arg preserved

Common causes

Using "$*" where separate arguments are needed

"$*" concatenates all parameters into a single word, so a command that expected several arguments receives just one.

Leaving $@ or $* unquoted

Unquoted, both undergo word splitting and globbing, so an argument with spaces is broken apart and any * expands against the filesystem.

How to fix it

Forward arguments with "$@"

Always use the quoted "$@" form to pass every positional parameter through unchanged.

wrapper.sh
#!/usr/bin/env bash
exec my-tool --flag "$@"

Use "$*" only to build one joined string

Reserve "$*" for cases where you deliberately want a single concatenated value, such as a log message.

bash
echo "invoked with: $*" >&2

How to prevent it

  • Default to "$@" for forwarding arguments.
  • Use "$*" only when you intend one joined string.
  • Never leave $@ or $* unquoted.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →