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
disownso 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.
sleep 60 &The shell immediately prints:
[1] 1842[1]: job number (used byjobs,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.
# Check that it is runningps -p 1842 -o pid,stat,comm PID STAT COMMAND 1842 S sleepCapture 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.
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:
my-long-command > output.log 2>&1 &MYPID=$!> output.log: redirects stdout to the file2>&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 >>:
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.
sleep 2 &PID=$!echo "Waiting for $PID..."wait $PIDecho "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.
# Start 3 operations in paralleltask_a &A=$!task_b &B=$!task_c &C=$!
# Wait for all 3 before going onwait $A $B $Cecho "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:
sleep 120 &MYPID=$!disown $MYPID
jobs # the job no longer appearsps -p $MYPID # but the process still runsdisown 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.
| Option | Effect |
|---|---|
disown $PID | Removes the job from jobs: the shell no longer relays SIGHUP to it |
disown -h $PID | Same protection, without removing it from jobs |
disown -a | Detaches 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.
command > output.log 2>&1 &disown $!Or in a more readable version in a script:
my-command > /var/log/my-command.log 2>&1 &PID=$!disown $PIDecho "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.
| Symptom | Likely cause | Solution |
|---|---|---|
| The background output shows up in the middle of your prompt | No redirection | Add > output.log 2>&1 & |
$! empty | No command has been started with & yet | Check that the command ends with & |
The job dies on disconnection despite & | SIGHUP relayed by the shell when the session closes | Add disown $PID after the launch |
wait $PID returns immediately | The process has already ended | Normal, check its exit code with echo $? |
| The job uses 100% CPU in the background | No implicit throttling | Start 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 $PIDwaits for a specific job to end and exposes its code in$?.disown $PIDprotects from the SIGHUP of a disconnection without restarting the command; a plainexitdoes 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
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
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Use nohup to keep a process running
A new full quiz with random questions
Work again only on the questions you missed