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.