Right, so you’ve started a long-running process in your terminal, something like a big database backup or a model training script. You’re about to log out for the day, but you can’t just Ctrl+C it. That would be like burning down the bakery because your bread’s still in the oven. So you do the sensible thing: you background it with Ctrl+Z and then type bg. Perfect. It’s now happily running in the background, and you can see it when you type jobs.

Now you can close your terminal and go home, right? Wrong. Go ahead, try it. I’ll wait.

…See? The process is gone. Murdered. The moment you closed that terminal, your shell sent a SIGHUP (hangup signal) to every single job in its job control table, which is essentially its list of children. Your backgrounded job was a child of the shell, and when the parent dies, it takes the kids with it. A bit dark, but that’s the Unix process model for you.

This is where disown enters the chat, looking cool and offering you a way out. Its entire job is to tell your shell: “Hey, you know that process I just backgrounded? I don’t want to be its parent anymore. Remove it from your job table. If you get a SIGHUP, don’t forward it to that one. It’s on its own.” It’s the process equivalent of giving your teenager emancipation.

How to Use disown (The Basics)

You use it on a job that your shell knows about. First, get the job list:

$ jobs
[1]  + running    python my_very_important_training_script.py

Then you can disown it by its job number (the [1]):

$ disown %1

And just like that, it’s been severed from the shell. You can check jobs again and it will be empty. That process is now a direct child of the init process (or on modern systems, systemd), the benevolent zombie king that adopts all orphaned processes. You can safely log out, and your script will continue its work, blissfully unaware that its original parent shell is now a pile of ashes.

The Three Flavors of disown

This is the part where the designers got a little clever, and honestly, it’s a bit of a footgun if you don’t know the flags. The disown command has three main modes:

# The Standard: Just remove it from the job table. It's already running in the background.
$ disown %1

# The Nuclear Option: Remove from job table AND make it ignore future SIGHUP signals itself.
$ disown -h %1

# The Clean Break: Remove from job table and, if it was stopped (with Ctrl+Z), send it a SIGCONT to make it run again. This is the one you usually want.
$ disown -a

Wait, what? Why would you need -h? Because if the process itself has chosen to ignore SIGHUP, great. But if it hasn’t, and your shell isn’t around to protect it anymore, something else (like a different terminal) could still send it a SIGHUP and kill it. The -h flag tells the process to actively set itself to ignore SIGHUP from that point on. It’s like giving it a SIGHUP-proof vest.

The -a flag is a lifesaver. Imagine you backgrounded a job that was stopped (you pressed Ctrl+Z). Running disown %1 on a stopped job… just disowns it. It stays stopped forever, like a forgotten statue. The -a flag says “disown it, and also whack it with a SIGCONT (continue signal) to get it moving again.” It’s the most common way to ensure the job actually keeps running after you cut it loose.

Common Pitfalls and The Gotcha

The biggest pitfall is forgetting that disown works on jobs, not on PIDs. You can’t just disown 12345. You have to use the job spec, like %1 or %python. If you need to disown by PID, you’re looking for a different tool: nohup.

Ah, and here’s the real kicker, the thing that gets everyone: disown does not redirect output. If your process is writing to stdout or stderr, it’s still going to try to write to the TTY that no longer exists. This often causes the process to error out with a “broken pipe” message. The solution? You should have thought of that before you started it.

The best practice is to always redirect output to a file (or /dev/null if you don’t care) when you know you might need to disown it later.

# Start it the right way from the beginning:
$ python my_script.py > /path/to/output.log 2>&1 &
[1] 2342

# Then you can safely disown it
$ disown -a %1

Trying to redirect output after it’s already running is a messy affair involving gdb and a plea to the old gods, so just get it right upfront. disown is a brilliant escape hatch for a running process, but it’s not a psychic—it can’t fix the problems you baked into it at launch.