Background
Today a co-worker, let’s call him Evan, was trying to retrofit the UNIX command nohup into a script that I originally developed, and was not having much luck. He was trying to debug a unstable server daemon that’s called by my script. The server daemon had been crashing for the better part of 2 weeks, and the vendor of this particular daemon was directing Evan to prefix the launching of the daemon with nohup. Seemed like a simple request, but nohup wasn’t behaving as he expected. Both Evan and the vendor support specialist, let’s call him Sal, were looking for a nohup.out file to be deposited in the directory where they were running my script. I initially thought that my script might be changing directories behind the scenes, causing the files to show up some where else. After a quick check I could find no evidence of any nohup.out files anywhere. I really didn’t have much experience with nohup either so I figured this was the perfect excuse to better understand how nohup works.
nohup
nohup stands for “no hangup”, and is a way to start a process up that is immune from being hungup. It’s typically invoked like this:
1 | nohup sleep 100 & |
This means that within UNIX, when a parent process spawns a child process, and the parent process is then sent the signal to hangup, the child process has been instructed via nohup to ignore that signal. At which point the child process then becomes a child process of the init process, i.e. the process with the PID of 1. The init process is the originating process of every process on a UNIX system. As always, an example can explain it better than I:
example #1 (simple nohup, without killing the parent process)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # start the command "sleep 5" nohup'd and backgrounded % nohup sleep 5 & [1] 32257 % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init root 32257 31977 0 21:36 pts/8 00:00:00 sleep 5 % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init [1]+ Done nohup sleep 5 |
example #2 (parent is killed, child remains)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # initially start 2 terminal windows up (termA & termB) # termA % nohup sleep 15 & [1] 32229 % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init root 32229 32195 0 21:30 pts/9 00:00:00 sleep 15 % exit # at this point termA has been destroyed (its PID was 32195) # termB % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init root 32229 1 0 21:30 ? 00:00:00 sleep 15 # notice how the sleep process is now owned by the parent process init (PPID 1) % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init root 32229 1 0 21:30 ? 00:00:00 sleep 15 % ps -eaf | egrep "[s]leep|[U]ID|[/]sbin/init" UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jun20 ? 00:00:01 /sbin/init % |
So Where was the nohup.out File?
After debugging this problem for a bit I realized that my co-worker Evan was attempting to use nohup in a C-shell (csh). Turns out that made all the difference. See if you can see it:
1 2 3 4 5 6 7 8 9 10 11 12 | # scenario 1 % nohup sleep 1 & [1] 32583 % [1] Done sleep 1 # scenario 2 % nohup sleep 1 & nohup: ignoring input and appending output to `nohup.out' [1] 32584 % [1]+ Done nohup sleep 1 |
Which of the above scenarios do you think is the C-shell? Which is the Bourne Shell? Scenario #1 is the C-shell & scenario #2 is the Bourne Shell. Why the difference? Using the commands which and whereis didn’t really help to answer why either, since they both turned up /usr/bin/nohup.
1 2 3 4 5 6 7 8 9 10 11 | # csh % which nohup /usr/bin/nohup % whereis nohup nohup: /usr/bin/nohup /usr/share/man/man1p/nohup.1p.gz /usr/share/man/man1/nohup.1.gz # sh % which nohup /usr/bin/nohup % whereis nohup nohup: /usr/bin/nohup /usr/share/man/man1p/nohup.1p.gz /usr/share/man/man1/nohup.1.gz |
I knew it was shell dependent but I couldn’t see why. So I turned to the C-shell man page, and here was my first clue.
hup [command] (+)
With command, runs command such that it will exit on a hangup signal and arranges for the shell to send it a hangup signal when the
shell exits. Note that commands may set their own response to hangups, overriding hup. Without an argument (allowed in only a
shell script), causes the shell to exit on a hangup for the remainder of the script. See also Signal handling and the nohup
builtin command.
The bit at the end mentioned that C-shell had its own builtin version of nohup. A light bulb immediately went off and I now knew why nohup was behaving differently between C-shell and Bourne shell. Because there were in fact 2 different versions of nohup. One was built into C-shell, while the other was an executable on the system located here, /usr/bin/nohup. The version built into C-shell apparently doesn’t automatically create the nohup.out file, you have to do this yourself by redirecting STDOUT and STDERR. Bourne shell, on the other hand, doesn’t have its own version of nohup, and so it relies on the one located at /usr/bin/nohup. This version of nohup does automatically create the nohup.out file.
Additionally when I referred to the man page for /usr/bin/nohup I noticed this comment:
NOTE: your shell may have its own version of nohup, which usually supersedes the version described here. Please refer to your shell’s doc-
umentation for details about the options it supports.
So I told Evan that if he wants to get the nohup.out file he needs to call it explicitly with the full path like this:
1 | /usr/bin/nohup sleep 10 & |
The following URLs proved useful in helping me to round out my understanding of nohup.
- How to keep a process running when I log out?
- nohup Execute Commands After You Exit From a Shell Prompt
- How to make processes stay alive after a logout
- nohup that doesn’t generate nohup.out
NOTE: For further details regarding my one-liner blog posts, check out my one-liner style guide primer.
