$0
is the name you use to run the script. $1
, $2
, and so forth are the script's positional parameters, which hold the values of the command-line arguments you passed when you ran the script.
As Gordon Davisson said, the book's author must've meant to say that running ./test Linux
would print Hello Linux
. When you do that, ./test
goes into to the special parameter 0
, and Linux
goes to into the first positional parameter 1
. The script expands that first positional parameter by preceding it with a dollar sign ($1
), just as you do with variables. If you had instead run ./test Hello Linux for Human Beings
, then in the script, $1
would expand to Linux
, $2
to for
, $3
to Human
, and $4
to Beings
.
You can write a simple script to try this out:
#!/bin/bash
echo "\$0 expands to '$0'."
echo "\$1 expands to '$1'."
echo "\$2 expands to '$2'."
echo "\$3 expands to '$3'."
(Go on as far as you want. For positional parameters higher than 9
, use the ${
}
form of parameter expansion, e.g., expand 10
by writing ${10}
. In scripts that work with many positional parameters, the special parameter @
is often used, avoiding repetition, but you can ignore that for now if you like.)
Try saving that in a file and marking the file executable, which you can do by running chmod +x simple
where simple
is replaced with the name of the file, if different. Then you can run it using commands like ./simple
, ./simple foo
, ./simple foo bar
, and so on.
You'll notice that when fewer than three command-line arguments are passed, positional parameters that correspond to the ones that weren't passed expand to the empty string. That's what happens when you attempt to expand a shell parameter that is not defined. You'll notice, further, that when more command-line arguments are passed, the ones past the third are not used. That's probably what you'd expect, since the script doesn't refer to them at all.
Now try running ./simple *
. The shell expands *
to all the filenames in the current directory except those that start with .
, so three of those will be shown as the first three positional parameters (or fewer if there aren't that many). You can try running it with other shell expansions, such as ./simple {5..10}
.
You can pass command-line arguments containing blanks by enclosing them in quotes. For example, try ./simple 'foo bar' baz
. Notice that $1
expands to foo bar
this time, and not just to foo
.
Because the shell performs various expansions, it's not always obvious how many command-line arguments you're passing to a command. An easy way to see what each argument will be is to replace the command with printf '[%s]\n'
. For example:
$ printf '[%s]\n' f*
[fonts]
[fstab]
[fuse.conf]
[fwupd]
$ printf '[%s]\n' {1,3}{a..c}
[1a]
[1b]
[1c]
[3a]
[3b]
[3c]
Since you've only recently started shell scripting, the Bash reference manual may be challenging, and you might not want to read it from front to back. But I think it's a valuable resource even if you consider yourself a complete beginner. You may find the section on shell parameters useful, since it starts with what you already know--shell variables--and moves on to special parameters like ?
(which people often call the $?
parameter, since that's how you expand it). For general learning about Bash, especially at a more introductory level, I recommend these pages, including BashGuide.
echo \'$0\' \"$1\"
and then run with different values and see for yourself)../test.sh Linux
. If you ran it with./test.sh foo bar baz
, then$0
would be "./test.sh",$1
would be "foo",$2
would be "bar", and$3
would be "baz".