and
newscript "a b c" 'd e' f g
would report 4. The command
shift $#
"erases" all parameters because it shifts them away, so it is lost forever.
$$ - Current process ID
The variable "$$" corresponds to the process ID of the current shell running the script. Since no two
processes have the same identification number, this is useful in picking a unique temporary filename. The
following script selects a unique filename, uses it, then deletes it:
#!/bin/sh
filename=/tmp/$0.$$
cat "$@" | wc -l >$filename
echo `cat $filename` lines were found
/bin/rm $filename
Click here to get file:
CountLines0.sh
Another use of this variable is to allow one process to stop a second process. Suppose the first process
executed
echo $$ >/tmp/job.pid
A second script can kill the first one, assuming it has permissions, using
kill -HUP `cat /tmp/job.pid`
The kill command sends the signal specified to the indicated process. In the above case, the signal is the
hang-up, or HUP signal. If you logged into a system from home, and your modem lost the connection, your
shell would receive the HUP signal.
I hope you don't mind a brief discourse into signals, but these concepts are closely related, so it is worth while
to cover them together. Any professional-quality script should terminate gracefully. That is, if you kill the
script, there should be no extra files left over, and all of the processes should quit at the same time. Most
people just put all temporary files in the /tmp directory, and hope that eventually these files will be deleted.
They will be, but sometimes the temporary files are big, and can fill up the /tmp disk. Also some people don't
mind if it takes a while for a script to finish, but if it causes the system to slow down, or it is sending a lot of
error messages to the terminal, then you should stop all child processes of your script when your script is
interrupted. This is done with a trap command, which takes one string, and any number of signals as an
argument. Therefore a script that kills a second script could be written using:
#!/bin/sh
# execute a script that creates /tmp/job.pid
newscript &
trap 'kill -HUP `cat /tmp/job.pid`' 0 HUP INT TERM
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
27 of 66
11/21/2011 12:03 PM
# continue on, waiting for the other to finish
Signals are a very crude form of inter-process communication. You can only send signals to processes running
under your user name. HUP corresponds to a hang-up, INT is an interrupt, like a control-C, and TERM is the
terminate command. You can use the numbers associated with these signals if you wish, which are 1, 2, and
15. Signal number zero is special. It indicates the script is finished. Therefore setting a trap at signal zero is a
way to make sure some commands are done at the end of the script. Signal 1, or the HUP signal, is generally
considered to be the mildest signal. Many programs use this to indicate the program should restart itself. Other
signals typically mean stop soon (15), while the strongest signal (9) cannot be trapped because it means the
process should stop immediately. Therefore if you kill a shell script with signal 9, it cannot clean up any
temporary files, even if it wanted to.
$! - ID of Background job
The previous example with $$ requires the process to create a special filename. This is not necessary if your
script launched the other script. This information is returned in the "$!" variable. It indicates the process ID of
the process executed with the ampersand, which may be called an asynchronous, or background process.
Here is the way to start a background process, do something else, and wait for the background job to finish:
#!/bin/sh
newscript &
trap "kill -TERM $!" 0 1 2 15
# do something else
wait $!
I used the numbers instead of the names of the signals. I used double quotes, so that the variable $! is
evaluated properly. I also used the wait command, which causes the shell to sleep until that process is
finished. This script will run two shell processes at the same time, yet if the user presses control-C, both
processes die. Most of the time, shell programmers don't bother with this. However, if you are running several
processes, and one never terminates (like a "tail -f)" then this sort of control is required. Another use is to
make sure a script doesn't run for a long time. You can start a command in the background, and sleep a fixed
about of time. If the background process doesn't finish by then, kill it:
#!/bin/sh
newscript &
sleep 10
kill -TERM $!
The $! variable is only changed when a job is executed with a "&" at the end. The C shell does not have an
equivalent of the $! variable. This is one of the reasons the C shell is not suitable for high-quality shell scripts.
Another reason is the C shell has a command similar to trap, but it uses one command for all signals, while
the Bourne shell allows you to perform different actions for different signals.
The wait command does not need an argument. If executed with no arguments, it waits for all processes to be
finished. You can launch several jobs at once using
#!/bin/sh
job1 &
pid=$!
job2 &
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
28 of 66
11/21/2011 12:03 PM