3. Traps. Asynchronous execution. Named pipes.
- 
We know that programs can respond to signals. We can add this capability to our scripts too. Bash provides a mechanism for this purpose known as a trap. Let's see a simple example:
vim trap-demo.shtrap-demo.sh#!/bin/bash
# trap-demo: simple signal handling demo
trap "echo 'I am ignoring you.'" SIGINT SIGTERM
for i in {1..5}; do
echo "Iteration $i of 5"
sleep 5
doneWhen we press Ctrl-c while the script is running, the script will intercept the signal and will respond to it by running the
echocommand. Let's try it:./trap-demo.shPress Ctrl-c a few times and see what happens.
 - 
It is more convenient to tell
trapto call a function in response to a signal, instead of a complex command. Let's see another example:vim trap-demo2.shtrap-demo2.sh#!/bin/bash
# trap-demo2: simple signal handling demo
exit_on_signal_SIGINT () {
echo "Script interrupted." 2>&1
exit 0
}
exit_on_signal_SIGTERM () {
echo "Script terminated." 2>&1
exit 0
}
trap exit_on_signal_SIGINT SIGINT
trap exit_on_signal_SIGTERM SIGTERM
for i in {1..5}; do
echo "Iteration $i of 5"
sleep 5
doneNote the inclusion of an exit command in each of the signal-handling functions. Without an exit, the script would continue after completing the function.
./trap-demo2.shPress Ctrl-c.
 - 
Bash has a builtin command to help manage asynchronous execution. The
waitcommand causes a parent script to pause until a specified process (i.e., the child script) finishes.This can be best explained by an example. We will need two scripts, a parent script, and a child script:
vim async-child.shasync-child.sh#!/bin/bash
# async-child: Asynchronous execution demo (child)
echo "Child: child is running..."
sleep 5
echo "Child: child is done. Exiting."This is a simple script that runs for 5 seconds.
vim async-parent.shasync-parent.sh#!/bin/bash
# async-parent: Asynchronous execution demo (parent)
echo "Parent: starting..."
echo "Parent: launching child script..."
./async-child.sh &
pid=$!
echo "Parent: child (PID= $pid) launched."
echo "Parent: continuing..."
sleep 2
echo "Parent: pausing to wait for child to finish..."
wait "$pid"
echo "Parent: child is finished. Continuing..."
echo "Parent: parent is done. Exiting."From this script we launch the child script. Since we are appending
&after it, the parent script will not wait for the child to finish executing but will continue running. Both of the scripts are now running in parallel. Immediately after launching the child, the parent uses the special variable$!to get the process ID (PID) of the child. This variable always contains the PID of the last job put into the background. Then, later in the parent script, we use the commandwaitto stop the parent from running any further, until the child script is finished. Let's try it:./async-parent.shAll the messages output from the parent are prefixed with
Parent:and all the messages output from the child are prefixed withChild:. This helps us understand the flow of execution. - 
Named pipes behave like files but actually form first-in first-out (FIFO) buffers. As with ordinary (unnamed) pipes, data goes in one end and emerges out the other.
With named pipes, it is possible to set up something like this:
process1 > named_pipe, an this:process2 < named_pipeand it will behave like this:process1 | process2. The only difference is thatprocess1andprocess2run in the current shell, not in a subshell, which makes named pipes more useful, even if they are a bit less convenient than using a pipe operator (|).A named pipe can be created with the command
mkfifo:mkfifo pipe1ls -l pipe1Notice that the first letter in the attributes field is "p", indicating that it is a named pipe.
ls -l > pipe1 &cat < pipe1This is similar to:
ls -l | catHowever the named pipe is more flexible, because the two commands connected by the pipe can be executed even in different terminals.
However these two examples are not the same thing:
echo "abc" | readecho $REPLYecho "abc" > pipe1 &read < pipe1echo $REPLYLet's remove
pipe1:rm pipe1 - 
Another example with a named pipe:
mkfifo pipe1while true; do read line < pipe1; echo "You said: '$line'"; done &echo Hi > pipe1echo Hello > pipe1echo "The quick brown fox jumped over the lazy dog." > pipe1fgPress Ctrl-c to stop the
whileloop.rm pipe1