1. Overview
The nohup command in Linux runs processes that should continue even after the user logs out or the terminal is closed.
In this tutorial, we’ll learn how to use nohup to run and manage long-running background processes.
2. Basics
In this section, we’ll learn about the HUP signal and how nohup protects a process from it.
2.1. Hang up Signal
First, let’s take a look at the sighup_demo.sh script that runs indefinitely:
$ cat sighup_demo.sh
#!/bin/sh
while true
do
sleep 2
echo "process is running ..."
echo "an error occurred ..." >&2
done
Our script prints to standard output (stdout) and standard error (stderr) streams within an infinite while loop.
Now, let’s run our script as a background process by appending & at the end:
$ ./sighup_demo.sh &
[1] 478
process is running ...
an error occurred ...
The process has started with a PID=478.
Further, let’s use ps to verify the state of the process:
$ ps -p 478
PID TTY TIME CMD
478 pts/0 00:00:00 sighup_demo.sh
Next, let’s use the kill command to send the HUP signal to our process:
$ kill -HUP 478
This simulates the scenario where a user logs out or closes the terminal where the process was started. Further, the job control mechanism updates the latest state of the background job internally.
Moreover, we can see that the shell notifies the latest state of the background job immediately when it receives the HUP signal from the same terminal window:
[1]+ Hangup ./sighup_demo.sh
It’s important to note that the visibility of background job IDs is limited to the parent terminal. So, the output “[1]+ Hangup” will only be visible in the parent terminal where we started the background job. Besides, if we send the HUP signal from a different terminal, the shell delays notifying the job state until the next user interaction.
Let’s use ps to get the latest status of the process:
$ ps -p 478
PID TTY TIME CMD
As expected, the process is no longer active.
2.2. No Hang Up (nohup)
First, let’s run our sighup_demo.sh script in the background with the nohup command:
$ nohup ./sighup_demo.sh &
[1] 506
Now, let’s send the HUP signal to the process:
$ kill -HUP 506
Since we used nohup to run our script, the process is immune to the HUP signal.
Lastly, we can use ps to verify that the process keeps running even after we send the HUP signal:
$ ps -p 506
PID TTY TIME CMD
506 pts/0 00:00:00 sighup_demo.sh
We can run this a few more times to confirm our hypothesis.
3. Handling Standard Output and Error
Let’s start a new background job with nohup to run our script:
$ nohup ./sighup_demo.sh &
[2] 1128
nohup: ignoring input and appending output to 'nohup.out'
We see a message on the terminal suggesting that the input is ignored while the output is appended to the nohup.out file.
Now, let’s use the tail command on nohup.out to see the stream of output:
$ tail -f nohup.out
process is running ...
an error occurred
process is running ...
an error occurred
Next, let’s see how we can segregate the error and output messages to different files with stream redirection:
$ nohup ./sighup_demo.sh 2>error.log 1>output.log &
[2] 1214
Lastly, we can use head to verify the content of output.log and error.log files:
$ head -3 output.log
process is running ...
process is running ...
process is running ...
$ head -3 error.log
nohup: ignoring input
an error occurred
an error occurred
Great! It looks like we’ve got this one right.
4. Handling Standard Input
First, let’s modify the signup_demo.sh script to accept user input by adding a few commands in its beginning:
$ head -7 sighup_demo.sh
#!/bin/sh
echo "Provide first input ..."
read first_input
echo "Provide second input ..."
read second_input
echo "first input: ${first_input}, second input: ${second_input}"
Now, let’s start a background job using the modified script:
$ nohup ./sighup_demo.sh &
[2] 3589
nohup: ignoring input and appending output to 'nohup.out'
Like in earlier runs, we see that input is ignored
Further, if we tail on nohup.out, we can see that the job is running, but the user inputs are blank:
$ tail -f nohup.out
Provide first input ...
Provide second input ...
first input: , second input:
process is running ...
an error occurred
To solve this, we can provide the input using a here document:
$ nohup ./sighup_demo.sh <<EOF &
entry1
entry2
EOF
[2] 1703
nohup: appending output to 'nohup.out'
Interestingly, we no longer see the message around input being ignored.
Lastly, let’s confirm that the background process accepted the input strings correctly:
$ tail -f nohup.out
Provide first input ...
Provide second input ...
first input: entry1, second input: entry2
process is running ...
an error occurred
process is running ...
an error occurred
Fantastic! We successfully handled standard input for the process running with nohup.
5. Conclusion
In this tutorial, we learned about the nohup command in Linux. Further, we explored its significance in managing long-running processes without being affected by the HUP signal.
Lastly, we learned how to handle standard input, standard output, and standard error streams for processes started with nohup.