Shell Scripting – Variables (Part 2)

0
68

There is a set of variables that are already available for use, and most of these variables cannot have values assigned to them. These can contain useful information, which can be used by the script to know about the environment in which it is running.

Also Read: Introduction to Shell Scripting

The first set of variables we will understand is $0 .. $9 and $#.
The variable $0 is the basename of the program.
$1 .. $9 are the first 9 additional parameters for calling the script.
The variable [email protected] is all parameters $1 .. whatever.

The variable $* is quite similar to the variable [email protected], but it does not preserve any whitespace and quoting, so “File with spaces” becomes “File” “with” “spaces”. This is like the echo stuff we discussed in Shell Scripting – Variables. As a general rule, use [email protected] and avoid using $*.
$# is the number of parameters the script was called with.

Let’s take an example script:

#!/bin/sh
echo "I was called with $# parameters"
echo "My name is $0"
echo "My first parameter is $1"
echo "My second parameter is $2"
echo "All parameters are [email protected]"

Let’s look at running this code and see the output:

$ /home/var.sh
I was called with 0 parameters
My name is /home/var.sh
My first parameter is
My second parameter is
All parameters are
$
$ ./var.sh hello good morning
I was called with 3 parameters
My name is ./var.sh
My first parameter is good
My second parameter is morning
All parameters are hello good morning

Note that the value of $0 changes depending on how the script was called. $# and $1 .. $9 are set automatically by the shell.

There is a method for taking more than 9 parameters. This can be done by using the Shift command.

Take a look at the script below:

var.sh
#!/bin/sh
while [ "$#" -gt "0" ]
do
echo "\$1 is $1"
shift
done

This script will keep on using shift, until the value of $# is down to zero, the point at which the list becomes empty.

There is another unique variable $? . This variable contains the exit value of the last command that was run. This can be shown by the code:

#!/bin/sh
/local/bin/my-command
if [ "$?" -ne "0" ]; then
echo "Sorry, a problem occurred!"
fi

This code will attempt to run /usr/local/bin/my-command which should exit with a value of zero if it was executed successfully, or exit with a nonzero value if it failed. We can then handle this by checking the value of $? after calling the command. This helps make scripts robust and more intelligent. Well-behaved applications should return zero on success.

The other two main variables set for you by the environment are $$ and $!. These are both process numbers.

The $$ variable is the PID (Process IDentifier) of the currently running shell. This can be useful for creating temporary files, such as /tmp/script.$$ which is useful if many instances of the script could be running at the same time, and they all need their own temporary files.

The $! variable is the PID of the last run background process. This is useful to keep track of the process as it gets on with its job.

Another interesting variable is IFS. This is the Internal Field Separator. The default value is SPACE TAB NEWLINE, but if we are changing it, it’s easier to take a copy, as shown:

var.sh
#!/bin/sh
old_IFS="$IFS"
IFS=:
echo "Please input some data separated by colons ..."
read a b c
IFS=$old_IFS
echo "a is $a b is $b c is $c"

This script runs like this:

$ ./ifs.sh
Please input some data separated by colons ...
hello:hope you are:doing fine
a is hello b is hope you are c is doing fine

Note that if you enter: “hello:hope you:are:doing:fine” then the output would be:

$ ./ifs.sh
Please input some data separated by colons ...
hello:hope you:are:doing:fine
x is hello y is hope you z is are:doing:fine

It is important to realize that when dealing with some variables like IFS in particular (but any variable not entirely under your control) that it could contain spaces, newlines, and other “uncontrollable” characters. It is, therefore, a very good idea to use double-quotes around it, ie: old_IFS="$IFS" instead of old_IFS=$IFS.