1. Overview

The nohup command is a useful Linux tool that lets us start a process and have it continue to run even if we close the terminal or lose our connection.

There can be some drawbacks to using this command, though.

For instance, nohup sends command output to a file called nohup.out by default. Some scripts may produce a large volume of unhelpful output, so saving it to a file may be undesirable.

The nohup command also generates messages in the terminal about output redirection and ignoring input, which can be intrusive or confusing. We may want to avoid these messages altogether.

In this tutorial, we’ll look at how nohup works and explore two methods to avoid generating nohup.out and the associated terminal messages.

2. Example Long-Running Process

Before we examine the nohup command in detail, let’s build a simple shell script to use as an example process:

$ cat simple.sh
#!/bin/bash
while true; do
   sleep 3
   date +"The current date and time is %F %T"
   ls missing.txt
done

Once we run simple.sh, the script prints the current date and time every three seconds. It also tries to list a specific file, missing.txt.

The script will keep running until we manually stop it — for instance, by pressing Ctrl-C.

Let’s see what happens when we run the script in a folder where simple.sh is the only file, and stop it after one iteration: 

$ ./simple.sh
The current date and time is 2023-03-08 01:07:54
ls: cannot access 'missing.txt': No such file or directory

The ./ in this example tells the shell to look for the script in the current working directory.

The output of the successful date command is sent to stdout, while the error from the ls command is sent to stderr.

We can verify this by redirecting the two standard streams to separate files using the > redirection operator and their integer file descriptors (1 for stderr and 2 for stderr):

$ ./simple.sh 1>simple.out 2>simple.err

$ cat simple.out
The current date and time is 2023-03-08 01:10:40

$ cat simple.err
ls: cannot access 'missing.txt': No such file or directory

We’ll come back to stdout and stderr as we explore nohup below.

3. Running a Script as a Background Process

A long-running process like the execution of our simple.sh script can tie up the terminal for an extended period of time. To avoid this, we can run the process in the background by appending the & operator to the end of the command:

$ ./simple.sh 1>simple.out 2>simple.err &
[1] 5281

In this example, our script started as job number 1, with process ID 5281. We can see that the job is still running using the ps command:

$ ps -o pid,cmd | grep 5281
5281 /bin/bash simple.sh

The -o cmd,pid option tells ps to show only the process ID and command name for each process. We then use the | operator to pipe the output from ps into the grep command, which returns only lines that contain the process ID (5281) of our running script.

4. The SIGHUP Signal

An important concept for understanding the nohup command is the SIGHUP (“hang-up”) signal.

In particular, when a Linux terminal is disconnected or closed, it sends a SIGHUP signal to its sub-processes, including any shell running in the terminal. The shell process receives the signal and sends it to its sub-processes in turn.

When a process receives a SIGHUP signal, the default action is to stop executing immediately. 

Thus, if we exit the terminal where we launched simple.sh as a background process, the process will stop executing.

We can see this by exiting the terminal and then starting a new terminal. When we run ps in the new terminal, our process is gone:

$ ps -o pid,cmd | grep 5281
    

If we want the process to continue running even when we exit the original terminal, we need to protect it from the hang-up signal. One way to do this is with the nohup command.

5. The nohup Command

A process started with the nohup (“no hang-up”) command ignores the SIGHUP signal when its parent Linux terminal is disconnected. This makes it a useful tool when we have long-running processes that may not finish during our interactive Linux sessions or when we have an unstable network connection.

A process started with nohup, however, does not inherit stdin (standard input), stdout, and stderr from the originating shell. Instead, the nohup command ignores stdin and redirects stdout and stderr to a file called nohup.out.

We can see this when we start our simple.sh script with nohup:

$ nohup ./simple.sh
nohup: ignoring input and appending output to 'nohup.out'

The process creates the nohup.out file in the directory where we run the script:

$ ls
nohup.out
simple.sh

If we let the script run for about 30 seconds and then kill it, the output in nohup.out looks like:

$ cat nohup.out
The current date and time is 2023-03-08 17:03:15
ls: cannot access 'missing.txt': No such file or directory
The current date and time is 2023-03-08 17:03:18
ls: cannot access 'missing.txt': No such file or directory
The current date and time is 2023-03-08 17:03:38
ls: cannot access 'missing.txt': No such file or directory
The current date and time is 2023-03-08 17:03:41
ls: cannot access 'missing.txt': No such file or directory
The current date and time is 2023-03-08 17:03:44
ls: cannot access 'missing.txt': No such file or directory

Some scripts can generate a lot of redundant output, making nohup.out not very useful. In addition, the input/output message that nohup generates when launching a process can be confusing and is also not generally useful.

Sometimes, therefore, we might want to suppress the creation of nohup.out and related messaging.

5.1. Redirecting stdout and stderr

To avoid generating the nohup.out file and related terminal messages, we can instead redirect stdout and stderr as we did in our earlier example.

$ nohup ./simple.sh 1>simple.out 2>simple.err &

Here, we again use the & operator to put the process in the background.

If we look at simple.out after one iteration of the loop, we see the expected date-time message:

$ cat simple.out
The current date and time is 2023-03-09 02:11:47

On the other hand, simple.err shows both our expected missing file error and the nohup message about ignoring input:

$ cat simple.err
nohup: ignoring input
ls: cannot access 'missing.txt': No such file or directory

To suppress the input message, we can tell nohup to read from the null device:

$ nohup ./simple.sh 0</dev/null 1>simple.out 2>simple.err &

Here, /dev/null is the Linux null device, which returns the end-of-file (EOF) symbol when we read from it. The file descriptor for stdin is 0 (zero).

Now, simple.err contains only our missing file error:

ls: cannot access 'missing.txt': No such file or directory

We can also use the null device to completely silence output from a process launched with the nohup command.

5.2. Suppressing nohup.out

If we want to suppress all visible output from a process launched with nohup, we can also redirect stdout and stderr to the null device:

$ nohup ./simple.sh 0</dev/null 1>/dev/null 2>/dev/null &

When we write to the null device, nothing happens.

There’s no output printed to the terminal, and no other files are produced. Assuming we’ve removed files generated from previous runs, the folder now contains only our script:

$ ls
simple.sh

We can run the ps command to verify that our script is running:

$ ps -o pid,cmd | grep bash
5412 /bin/bash simple.sh

We can also use a shorthand notation to achieve the same result:

$ nohup ./simple.sh </dev/null >/dev/null 2>&1 &

Here, the < operator with no filehandle defaults to reading from stdin. Likewise, the > operator defaults to writing to stdout.

Finally, 2>&1 redirects stderr to stdout, merging the two standard streams.

6. Conclusion

In this article, we used the nohup command to launch a long-running script that continues to execute even after its parent terminal exits.

We then examined two methods for suppressing the output that nohup generates by default.

First, we saw that we could redirect stderr and stdout to files of our choosing. This is a valuable tactic when we want to keep the output generated from our process but want to separate error messages from other process output.

Finally, we used the null device to completely suppress all standard output and standard error from a process launched with nohup.