Course outline · 0% complete

0/29 lessons0%

Course overview →

Arguments: $1, $2, and $#

lesson 8-2 · ~8 min · 22/29

Scripts that take input

Running ./backup.sh notes.txt hands the script notes.txt as an argument, exactly like the arguments given to ls and grep since lesson 1-3. Inside the script, a set of special variables makes those arguments available:

VariableHolds
$1, $2, $3The first, second, and third arguments
$#How many arguments were passed
$0The script's own name
"$@"All the arguments at once, which unit 9 loops over

There is a handy trick for exploring these without creating a file each time. Running set -- Ada Grace fills $1 and $2 as though the script had been called with those two arguments.

Reading arguments back with set --

set -- simulates being called with two arguments, and the echo lines then read them back through the positional variables.

set -- Ada Grace
echo "First guest: $1"
echo "Second guest: $2"
echo "Total guests: $#"

Output

First guest: Ada
Second guest: Grace
Total guests: 2

$1 and $2 picked up the values in the order they were given, and $# reported 2 without being told the count anywhere. That count is derived from the arguments themselves, so it tracks whatever is passed in.

One script, two different calls

Here is the real thing: a one-line backup.sh that uses $1, invoked twice with different arguments. Calling it as bash backup.sh ... is the run-without-chmod form from lesson 8-1.

echo 'echo "Backing up $1 to $1.bak"' > backup.sh
bash backup.sh notes.txt
bash backup.sh photos.zip

Output

Backing up notes.txt to notes.txt.bak
Backing up photos.zip to photos.zip.bak

The file on disk never changed between those two runs, yet the output did. That is the entire purpose of arguments: one script describes the procedure, and the argument supplies the subject it operates on.

For a script run as ./ship.sh box1 box2 box3, the value of $# is 3 and the value of $2 is box2.

$# counts only the arguments, and there are three boxes. The script's own name lives separately in $0 and is deliberately excluded from the count, so $# answers how much input arrived rather than how many words were on the command line.

A single-line script can use $1 and $# together, mixing one specific argument with the total count. Writing it with echo '...' > greet.sh keeps the single quotes on the outside so the inner double quotes and the dollar signs land in the file unexpanded.

echo 'echo "Hello, $1! You are guest number $#"' > greet.sh
bash greet.sh Ada
bash greet.sh Grace Hopper

Output

Hello, Ada! You are guest number 1
Hello, Grace! You are guest number 2

Comparing the two calls shows both variables reacting independently. The first call passes one argument, so $1 is Ada and $# is 1. The second passes two, Grace and Hopper, so $1 is still just the first of them while $# rises to 2.