More on keeping commands running after exiting the Linux terminal

Photo by Braden Collum on Unsplash

I wrote a while back an article about the nohup command which allows a running Linux command to keep running even after exiting the terminal. The magic happens because nohup will make a process ignore the SIGHUP signal, which is broadcasted when exiting a terminal. Then in another article I was explaining how signals communicate with Linux processes and are able to send commands to them.

So the whole thing demystified means that Linux processes are handling SIGHUP signals by default by exiting, and this SIGHUP signal is sent automatically when exiting a terminal. Add the two together and you get the well known and sometimes annoying result: your long running copy command stops when exiting a SSH connection to your remote server.

So then the solution to all this comes naturally: why don’t we make it so that the copy command ignores the SIGHUP signal? That way the terminal would exit, the SIGHUP signal would be broadcasted but when it reaches our copy command, it would do nothing. It would be ignored. And that is exactly what the nohup command does, as explained before.

But things go a little deeper if you wish to know, which opens the magic box a bit more and gives another tool that we can use to achieve the same thing. You see, there was a carefully avoided unknown in the previous paragraphs: the SIGHUP event is broadcasted…where? Surely not all processes running are closed, that would mean a total system reboot. Maybe all processes started by the logged in user? No, because I close terminals all day long on my desktop session and the graphics system does not go away, nor do all the other started apps. So what is happening then?

The power of the Linux shell

Photo by Brandon Jaramillo on Unsplash

Let’s consider an interactive Linux script, or a program that asks the user if they are certain they want to do an operation on a file. In the terminal, who allows the program to asks questions? And who allows the user to answer? Yes, the shell.

The shell reads input from the user and displays output from the program. The shell also allows a program to run in the background by using the bg command, or to come back in the foreground by using the fg command. The shell is also able to run programs straight in the background by adding an & at the end of the command line and is able to interrupt the execution of a program by pressing ctrl+z. The shell intermediates the communication between the user and the foreground program and it displays the output of foreground and background programs.

So the shell has a lot to say about running processes. It is only natural for it to keep track of them in a list. To know which are in the background, which is in the foreground, which are interrupted and which it needs to close when the terminal exits.

Linux shell jobs

Photo by Jo Szczepanska on Unsplash

So then, as we already know, each time you run a Linux application it will start in a process. The process itself has a lot going on and we will talk about it in another article, but there is one more thing happening when you start a program in a Linux shell: a job is created. The shell job is not a process, it’s a sort of identifier for a task that is currently running. It’s like a named pointer to the running process.

Also, the shell job has nothing to do with the kernel: it’s a shell construct. It exists in the shell and the Linux commands we use to inspect the shell jobs are shell commands, not Linux programs. We can see the Linux jobs by using the jobs command. Let’s see an example:

#ping > /dev/null &

We are starting a long running task by pinging a random Internet target. We send the ping output to /dev/null because we are not interested in what it has to say. Finally, we start the command in the background by adding &. The result will be the following:

Running a background task

We know that 44191 is the process ID. But can you guess what [1] is? Yes, it’s the job ID. A job has been created by this Linux shell and it’s the first one so it gets ID 1. If we open another shell and start another ping, it will have the job ID 1. Jobs are a shell construct and they are scoped to it. Each opened shell will have its own job table.

Ok, let’s see what we have in the jobs table by using the jobs command:

Inspecting the shell jobs table

We have one running job. We can see the process ID too by adding the -l parameter:

A more complete picture of the running jobs

The plus beside the [1] job ID means it’s the last job that was started. Let’s start another one:

Two jobs running, the second one was the last

We can bring the last job to the foreground by running fg or we can bring the first job to the foreground by running fg %1:

Bringing the first job to the foreground

Exiting a terminal and cleanup

Photo by Marek Studzinski on Unsplash

When we exit a terminal, the shell running there is responsible for cleaning up: it will send the SIGHUP event to all processes in its jobs list. So then, yes we can use nohup to make the processes ignore the SIGHUP signal, but now that we know about the jobs list we opened up another possibility. Could we edit the jobs list?

And here comes the disown command. Again, not a program but a shell command because it deals with shell constructs. Disown allows us to remove jobs from the jobs table:

Removing a job from the jobs table

I started a long running task above, I checked to see it’s in the jobs table by using the jobs command: it’s there, and then I used disown on it and behold: the jobs table no longer knows anything about it. But is the process still running?

The ping process is still there

Yes it is, we can see it with the ps command, the process is definitely still running but it’s no longer tracked by the shell. We cannot bring it in the foreground using fg, we cannot communicate with it via the terminal: the shell lost all its power over it.

The shell has no knowledge of my ping process anymore

This makes things interesting because it means we can close the shell and it will know nothing about our running ping. But there’s more:

Whan are the powers of disown?

Look at that -h parameter. It’s as if disown was created specifically with this role in mind: allowing us to end a Linux terminal session without closing our running tasks. The -h parameter will make all jobs ignore the SIGHUP signal (or just the desired job if we specify it). So we have come full circle, back to the nohup command, but this time with a lot more knowledge about what’s really happening behind the scene, and done by a different command, disown.

I hope you had fun reading this article. I hope it shed some light on the way Linux works. For me, learning about the shell jobs, although such a small and uninteresting subject, brought a sense of control as I understood part of what is happening when a shell ends its life. See you in the comments and in the next article!




Still planning that trip to the Moon.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How To Implement Shift Left Testing Approach

Feed Your Boredom

Cat Pictures — Tryhackme CTF Writeup

Recipe OSS: How to create a symbolic link? (Alibaba Cloud)

Tailwind CSS Set a Minimum Font Size

Power BI DAX Context Transition — Behind the scenes

Case Study Of Ios Routers

We’re a go Red Leader

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Radu Zaharia

Radu Zaharia

Still planning that trip to the Moon.

More from Medium

One Minute Bash Tip: Ping Timing

Things to know about gvfs

Linux: sum a column of numbers

Using SSH in a secure and convenient way