Q1What goes into $2 when you run ./a.sh foo bar?
Shell Script - Arguments and Exit Codes
Receive ./a.sh foo bar values with $1 $2 $@ $# $0, supply a default with ${2:--}, check $? and return success or failure with exit 0 / exit 1 — write and run a practical script, illustrated in a browser terminal.
Receiving arguments — $1 / $2 / $0
Scripts can take values when you run them.
Values you list after the command, like ./a.sh foo bar, are called arguments, and inside the script $1 is the first and $2 is the second.
$0 is the script's own name, $# is the number of arguments passed, and $@ stands for all of them together.
With these you can run the script with different input every time instead of with fixed values.
| Syntax | Meaning | Example |
|---|---|---|
$1 $2 | First and second arguments | echo "$1 then $2" |
$0 | The script's own name | echo "running $0" |
$# | Number of arguments passed | echo "argc=$#" |
$@ | All arguments together | echo "all: $@" |
$1 $2; $# gives the count and $@ the whole set.set -- foo bar # set positional parameters for demo
echo "1st: $1" # foo
echo "2nd: $2" # bar
echo "argc: $#" # 2
echo "all: $@" # foo bar
Supplying a default — ${1:-def}
Sometimes no argument is passed.
If you write ${1:-default}, default is used when $1 is unset or empty, and the given value is used when one is provided.
This lets you write a script that follows the argument when given, and runs on a safe default when not.
Checking $# also tells you whether the expected number of arguments arrived.
| Syntax | Meaning | Example |
|---|---|---|
${1:-def} | Use def when $1 is unset | name=${1:-guest} |
${2:-def} | Use def when $2 is unset | sep=${2:--} |
${2:--}, passing a second value uses it, and omitting it uses the default -.set -- # reproduce running with no arguments
echo "${1:-guest}" # unset, so guest
set -- alice # now the first argument is set
echo "${1:-guest}" # has a value, so alice
Returning success or failure — $? and exit N
When a command finishes it returns an exit code, a number from 0 to 255.
By convention 0 means success and anything other than 0 means failure.
You can read the previous command's exit code with $?.
For grep it is 0 when found and 1 when not, so the value changes with the result.
From inside a script you set the exit code explicitly with exit N.
Returning exit 0 for success and exit 1 for failure is the common convention.
The caller receives this value through $? or && || and can use it for control such as proceeding only on success.
If you omit exit, the exit code of the last command run is returned as it is.
| Syntax | Meaning | Example |
|---|---|---|
$? | Exit code of the previous command | grep x f; echo $? |
exit N | End the script with exit code N | exit 1 |
exit 0 on success and exit 1 on failure, and the caller reads the result with $?.printf 'apple\nbanana\n' > fruits.txt # create the material
grep apple fruits.txt > /dev/null
echo "found? $?" # found, so 0
grep mango fruits.txt > /dev/null
echo "found? $?" # not found, so 1
Processing every argument in turn — $@ and $#
When the number of arguments isn't fixed, instead of writing $1 $2 one by one, loop over $@ with for to process as many as were passed.
The form for x in "$@"; do … done takes them one at a time, and showing the count with $# lets the same script handle any number of arguments.
This is a common pattern in tools that process several files together.
| Syntax | Meaning | Example |
|---|---|---|
"$@" | Pass every argument one word at a time (for for; needs double quotes) | for x in "$@"; do |
$# | Number of arguments passed | echo "count=$#" |
$#, then take each argument one at a time with $@ in a for loop to process them.set -- foo bar baz # set positional parameters for demo
echo "argc: $#" # 3
for x in "$@"; do
echo "- $x" # - foo / - bar / - baz
done
Knowledge Check
Answer each question one by one.
Q2Which is the correct meaning of ${1:-guest}?
Q3Which reads the exit code that shows whether the previous command succeeded?