Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Run a command in the background on Linux

By updated

Improve this page

Adding & at the end of a command is enough to run it in the background. The shell gives the prompt back immediately and the process keeps running. Combined with a redirection and disown, it is the basis for running long jobs without blocking your session, and for making them survive an SSH disconnection. The behaviours described here were checked with Bash 5.2 on Debian 13, Ubuntu 24.04 and AlmaLinux 10.

What you will learn

  • Run any command in the background with &
  • Get the PID of the job with $!
  • Redirect the stdout and stderr of a background process correctly
  • Wait for one or several jobs to end with wait
  • Detach a job from the shell with disown so that it survives the closing

In which context?

The background helps as soon as a command lasts longer than your patience, or when several independent jobs can run at the same time. Three situations keep coming back on a server:

  • You start a backup, a compilation or a download and want to keep using the terminal.
  • You want to parallelise several operations in a script.
  • You started a command in the foreground and want to make it independent from your SSH session.

Run a command in the background

The & operator at the end of a line runs the command in the background: the shell does not wait for it to end and gives control back at once.

Terminal window
sleep 60 &

The shell immediately prints:

[1] 1842
  • [1]: job number (used by jobs, fg, bg)
  • 1842: PID of the process

The prompt is back and the command runs in parallel. To check it, query the process by its PID with ps -p: the state S (sleeping) or R (running) confirms it is alive, an empty output that it has ended.

Terminal window
# Check that it is running
ps -p 1842 -o pid,stat,comm
PID STAT COMMAND
1842 S sleep

Capture the PID with $!

The special variable $! holds the PID of the last command started in the background. Capture it immediately in a variable of your own: the next & overwrites its value, and you would lose any reference to the previous job.

Terminal window
sleep 30 &
MYPID=$!
echo "The job runs with PID: $MYPID"

Redirect the output of a background process

A background process stays attached to the terminal for its output. Without a redirection, stdout and stderr show up there asynchronously, in the middle of what you type: nothing is lost, but everything gets mixed. So always redirect the background processes that produce output:

Terminal window
my-long-command > output.log 2>&1 &
MYPID=$!
  • > output.log: redirects stdout to the file
  • 2>&1: redirects stderr to the same file
  • &: puts it in the background

The order matters: > output.log must come before 2>&1. To append to an existing log file rather than overwrite it, use >>:

Terminal window
my-command >> /var/log/my-script.log 2>&1 &

Wait for a job to end: wait

wait blocks the shell until the named process ends, then puts its exit code in $?: 0 for a success, anything else for a failure. Read $? right after, the slightest intermediate command overwrites it.

Terminal window
sleep 2 &
PID=$!
echo "Waiting for $PID..."
wait $PID
echo "Finished with exit code: $?"

Parallelise and wait

wait accepts several PIDs and only gives control back when all have ended. It is the synchronisation point of a script that starts several independent jobs, far more reliable than an arbitrary sleep, too short or too long depending on the day.

Terminal window
# Start 3 operations in parallel
task_a &
A=$!
task_b &
B=$!
task_c &
C=$!
# Wait for all 3 before going on
wait $A $B $C
echo "All finished"

Detach a job from the shell: disown

When your shell receives SIGHUP, because the SSH connection or the terminal closes, it relays it to all its jobs before quitting (man bash), which kills them. Measured on Debian 13 and AlmaLinux 10: a sleep started with & dies when the shell receives SIGHUP, but survives a plain exit, the huponexit option being disabled by default.

disown removes a job from the shell's job list, which therefore no longer relays that SIGHUP to it. It accepts a PID as well as a job number:

Terminal window
sleep 120 &
MYPID=$!
disown $MYPID
jobs # the job no longer appears
ps -p $MYPID # but the process still runs

disown variants

The three forms differ by what they leave in the job table: keeping the job visible still lets you bring it back with fg, removing it makes it independent for good.

OptionEffect
disown $PIDRemoves the job from jobs: the shell no longer relays SIGHUP to it
disown -h $PIDSame protection, without removing it from jobs
disown -aDetaches every job

disown -h is useful if you want to still be able to use fg or jobs on the job.

Full launch in one line

The full pattern for a long job that resists disconnection gathers the three building blocks of the page: the redirection provides a log you can read, the & frees the prompt, and disown protects the job from the SIGHUP of the end of session.

Terminal window
command > output.log 2>&1 &
disown $!

Or in a more readable version in a script:

Terminal window
my-command > /var/log/my-command.log 2>&1 &
PID=$!
disown $PID
echo "Job started, PID=$PID, output in /var/log/my-command.log"

Troubleshooting

Most surprises come from the fact that & does only one thing: free the prompt. It does not redirect the output, does not protect from SIGHUP and does not lower the priority; each line of the table adds the missing building block.

SymptomLikely causeSolution
The background output shows up in the middle of your promptNo redirectionAdd > output.log 2>&1 &
$! emptyNo command has been started with & yetCheck that the command ends with &
The job dies on disconnection despite &SIGHUP relayed by the shell when the session closesAdd disown $PID after the launch
wait $PID returns immediatelyThe process has already endedNormal, check its exit code with echo $?
The job uses 100% CPU in the backgroundNo implicit throttlingStart it with nice -n 15 command & to lower its priority

Key points

  • command & runs in the background and gives the prompt back immediately.
  • $! holds the PID of the last background job, capture it right away.
  • Always redirect stdout and stderr: command > out.log 2>&1 &.
  • wait $PID waits for a specific job to end and exposes its code in $?.
  • disown $PID protects from the SIGHUP of a disconnection without restarting the command; a plain exit does not kill a running job.

Knowledge check

Check that the essentials of this guide stuck. The questions cover only what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn