bg, fg, &, jobs, nohup and disown

The ampersand “&” in the UNIX command line is used to launch commands or scripts from the shell or foreground to the background. When we send a process to the background we can’t interact with it through stdin but stdout is still sent to the screen unless diverted to some other file. Additionally, terminating our shell session will terminate the job/s still running in the background.

Let’s look at an example to make sense of it:

# cat /tmp/sleeptalk.sh
#!/bin/bash
.
while [ true ]
do
__echo “Talk talk at `date`”
__sleep 2
done
.
exit 0
root:/tmp> /tmp/sleeptalk.sh                             -> we launch the process …
Talk talk at Tue Oct 20 21:17:14 BST 2015
Talk talk at Tue Oct 20 21:17:16 BST 2015
Talk talk at Tue Oct 20 21:17:18 BST 2015
^Z
[1]+ Stopped ./sleeptalk.sh                              -> … and stop it with Control+Z
.
root:/tmp> /tmp/sleeptalk.sh                             -> we launch a second process …
Talk talk at Tue Oct 20 21:17:14 BST 2015
Talk talk at Tue Oct 20 21:17:16 BST 2015
Talk talk at Tue Oct 20 21:17:18 BST 2015
^Z
[2]+ Stopped ./sleeptalk.sh                              -> … and stop it again with Control+Z
.
root:/tmp> jobs                                          -> list the jobs in the background
[1]­- Stopped ./sleeptalk.sh
[2]+ Stopped ./sleeptalk.sh
.
root:/tmp> jobs -­l                                       -> list the jobs in the background with PIDs
[1]­- 31846 Stopped (tty input) ./sleeptalk.sh
[2]+ 31873 Stopped ./sleeptalk.sh
.
root:/tmp> jobs ­-r                                       -> list running jobs
root:/tmp> jobs -s                                       -> list stopped jobs
[1]-­ Stopped ./sleeptalk.sh
[2]+ Stopped ./sleeptalk.sh
.
root:/tmp> bg 1                                          -> restart job 1 in background
[1]­- ./sleeptalk.sh &
root:/tmp> Talk talk at Tue Oct 20 21:29:50 BST 2015
Talk talk at Tue Oct 20 21:29:52 BST 2015
Talk talk at Tue Oct 20 21:29:54 BST 2015
root:/tmp> fg 1                                          -> bring job 1 to foreground
Talk talk at Tue Oct 20 21:29:56 BST 2015
Talk talk at Tue Oct 20 21:29:58 BST 2015
^C                                                       -> we cancel job 1 with Control+C

Most often when we send jobs to the background with bg or at launch time with &, we will divert the stdout to some file so as not to get the terminal cluttered with output. We might still have stderr sent to the terminal if we want to know about any error though. Let’s look at two examples:

root:/tmp> ./sleeptalk.sh > /tmp/sleeptalk.log &
.
root:/tmp> ./sleeptalk.sh > /tmp/sleeptalk.log 2>&1

The 1st example diverts stdout to the log file and launches the script in the background but, as stderr still goes to the terminal, we should see any errors if they occurred.

The 2nd example diverts both stdout and stderr to the same log file but the script is launched in the foreground. We might want to do that if we want to check that the script is running smoothly (no errors) for a few seconds before we stop it (Control+Z) and send it to the background (bg).

The approach in either of those two examples is perfectly reasonable for short running jobs. But for long running jobs there is the danger that our shell session might terminate (network hiccups, inactivity timeouts, etc) and all its children would be marked for the kill. In that case, what we need is for the child process to…

1. ignore any SIGHUP signal received (SIGHUP = controlling terminal closed/dead)
2. divert stdin from the keyboard to /dev/null
3. divert stdout from screen to /dev/null unless it has already been diverted
4. divert stderr from screen to stdout

We can do that in 2 ways:

root:~> nohup /tmp/sleeptalk.sh > /tmp/sleeptalk.log 2>&1 &
.
root:~> /tmp/sleeptalk.sh > /tmp/sleeptalk.log 2>&1
^Z
root:~> jobs -­l
[1]+ 3034 Stopped /tmp/sleeptalk.sh > /tmp/sleeptalk.log 2>&1
root:~> bg 1
[1]+ 3034 Stopped /tmp/sleeptalk.sh > /tmp/sleeptalk.log 2>&1
root:~> disown ­-h -­a

The 1st command we run is to launch the script in the background (“&”), with stdout & stderr diverted to the log file, stdin blocked and with SIGHUP signal set to be ignored (“nohup”).

The 2nd command launches the script and diverts stdout & stderr, but the script is running in the foreground and any SIGHUP signal will kill it. So we stop it (Control+Z), restart it in the background (bg) and disown it with the flags -a (all jobs) and -h (ignore SIGHUP). We could also have used the flag -r (disown only running jobs) or the job number (e.g. disown -h %1).

<< pgrep                       stty, tty, clear & reset >>