Bash positional parameters are the numbered variables ($1, $2, $3, …) that hold the arguments passed to a script or function. You use them to make your scripts accept input from the command line, like ./myscript.sh file.txt backup, where $1 becomes file.txt and $2 becomes backup. This guide explains how they work, how to handle more arguments than you expect, and common pitfalls.
Formula
There is no mathematical formula for positional parameters; they are simply the words you type after the script name. The shell splits the command line on whitespace (spaces, tabs, newlines) and assigns each word to $1, $2, and so on. $0 holds the script name itself. The special variable $# holds the count of arguments, and $@ or $* expands to all arguments.
In the calculator above, you enter up to three sample arguments (as text) and the count. It shows you how the shell would see them: the count, the first argument, and a joined string of all three. The expressions are trivial because the shell does the real work; the calculator just illustrates the concept.
Worked Example
Take the defaults: argc = 3, arg1 = "hello", arg2 = "world", arg3 = "42".
- Count:
argc= 3 - First:
arg1= hello - All:
arg1 + " " + arg2 + " " + arg3= hello world 42
This matches what Bash would do if you ran ./script.sh hello world 42. The shell sets $1 to hello, $2 to world, and $3 to 42.
How Positional Parameters Work in Bash
When you run a script or call a function, Bash assigns each argument to a positional parameter. The first argument goes to $1, the second to $2, and so on. You can reference them directly in your script. For example:
#!/bin/bash
echo "Script name: $0"
echo "First arg: $1"
echo "Second arg: $2"
echo "Number of args: $#"
If you save that as test.sh and run ./test.sh apple banana, you get:
Script name: ./test.sh
First arg: apple
Second arg: banana
Number of args: 2
Positional parameters also apply to functions. Inside a function, $1 refers to the first argument passed to that function, not to the script’s arguments. This is a common source of confusion.
Shifting and Looping Over Arguments
The shift command moves all positional parameters left by one. $2 becomes $1, $3 becomes $2, and so on. The old $1 is discarded, and $# decreases by one. This is useful for processing arguments one by one:
#!/bin/bash
while [ $# -gt 0 ]; do
echo "Processing: $1"
shift
done
Running ./loop.sh a b c prints:
Processing: a
Processing: b
Processing: c
You can also loop directly over "$@" without shifting:
for arg in "$@"; do
echo "Arg: $arg"
done
Always quote "$@" to preserve arguments that contain spaces. Without quotes, $@ splits each argument on whitespace again, which breaks filenames like my file.txt.
Special Parameters: $@, $*, $#, $0
Bash provides several related special variables:
$0— the script name or function name (for functions, it’s the function name).$#— the number of positional parameters.$@— all positional parameters as separate words. When quoted ("$@"), each parameter stays intact.$*— all positional parameters as a single word. When quoted ("$*"), they are joined with the first character ofIFS(usually a space).
The difference between "$@" and "$*" matters when an argument contains spaces. For example, with arguments "hello world" and "foo bar":
"$@"expands to two separate items:hello worldandfoo bar."$*"expands to one item:hello world foo bar.
In practice, use "$@" almost always. It behaves the way users expect.
Setting Positional Parameters with set
You can manually set positional parameters using the set builtin. This is handy for testing or for re-parsing a string:
set -- one two three
echo "$1" # prints one
echo "$#" # prints 3
The -- prevents the first argument from being interpreted as an option. You can also split a string into positional parameters:
str="a b c"
set -- $str
echo "$2" # prints b
Be careful: unquoted $str splits on any whitespace, so this is fragile for filenames. Use read -a or mapfile for robust splitting into arrays.
Common Mistakes and Pitfalls
Several errors trip up both beginners and experienced scripters:
- Forgetting to quote:
echo $1works, but if$1contains spaces, it gets split. Useecho "$1". - Using $10 when you mean ${10}:
$10is interpreted as$1followed by a literal0. For the tenth parameter, use${10}. - Assuming $0 is the full path:
$0is whatever you typed to invoke the script. If you run./script.sh,$0is./script.sh. To get the absolute path, use$(readlink -f "$0")or$(realpath "$0")if available. - Modifying parameters in a function: Inside a function,
$1is the function’s first argument, not the script’s. If you need the script’s arguments inside a function, pass them explicitly or store them in global variables. - Using $* instead of $@:
$*joins all arguments into one word, which can break loops. Prefer"$@".
Alternatives: Arrays and getopts
For more than a handful of arguments, positional parameters become unwieldy. Bash arrays offer a more flexible way to store and iterate over values:
args=("$@")
echo "First: ${args[0]}"
echo "All: ${args[@]}"
For options like -f file or -v, the getopts builtin is the standard tool. It parses short options and stores the option character in a variable, and the argument (if any) in $OPTARG. Positional parameters remain for non-option arguments.
while getopts ":f:v" opt; do
case $opt in
f) file="$OPTARG" ;;
v) verbose=1 ;;
\?) echo "Invalid option" ;;
esac
done
shift $((OPTIND-1))
After the loop, shift $((OPTIND-1)) removes the processed options, leaving only the remaining positional parameters in $1, $2, etc.
Frequently Asked Questions
How do I get the last argument passed to a script?
Bash doesn’t have a direct $last variable, but you can use ${@: -1} (note the space before the minus) or ${!#}. The latter expands to the last positional parameter because $# is the count, and ${!n} gives the value of the variable named by n. For example, ${!#} with three arguments expands to ${3}.
What is the difference between $@ and $*?
Unquoted, both expand to all arguments, but they behave differently when quoted. "$@" preserves each argument as a separate word, even if it contains spaces. "$*" joins all arguments into one word, using the first character of IFS (usually a space) as the separator. Use "$@" unless you specifically need a single string.
Can I change the value of a positional parameter?
Yes, you can assign to $1, $2, etc., directly. For example, $1="new value" works. You can also use set -- newarg1 newarg2 to replace all positional parameters at once. This is often used after parsing options.
Why does $10 not work as the tenth argument?
Bash parses $10 as $1 followed by the literal character 0. To reference the tenth parameter, you must use braces: ${10}. This applies to any parameter number above 9.
How do I count the number of arguments passed to a function?
Inside a function, $# gives the number of arguments passed to that function, not to the script. If you need the script’s argument count inside a function, pass it as a parameter or store it in a global variable before calling the function.
What happens if I pass no arguments at all?
If you run a script with no arguments, $# is 0, and $1, $2, etc., are unset. Referencing an unset variable in an unquoted context expands to an empty string; in a quoted context, it also expands to nothing. You can check with [ $# -eq 0 ] to handle the no-argument case gracefully.
Related
Formula used
in argc | Number of arguments | - | 3 | 0 | 20 in arg1 | First argument | - | hello | 0 | 100 in arg2 | Second argument | - | world | 0 | 100 in arg3 | Third argument | - | 42 | 0 | 100 out count | Count of arguments | - | argc | 0 out first | First argument | - | arg1 | 0 out all | All arguments joined | - | arg1 + " " + arg2 + " " + arg3 | 0
Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It