Bring background jobs to the foreground
The fg command is a shell builtin that brings background jobs to the foreground, allowing you to interact with them directly. It's an essential tool for job control in Unix/Linux environments, particularly useful when working with long-running processes or multiple tasks simultaneously.
fg [job_spec]
Where:
job_spec - Job identifier (optional): %n, %string, %?string, %%, %+, %-| Format | Description |
|---|---|
%n |
Refers to job number n |
%string |
Refers to job whose command begins with string |
%?string |
Refers to job whose command contains string |
%% or %+ |
Refers to current job (most recently stopped or backgrounded) |
%- |
Refers to previous job |
Starting a process, suspending it, and bringing it back to foreground:
$ vim /etc/hosts
# Press Ctrl+Z to suspend
[1]+ Stopped vim /etc/hosts
$ jobs
[1]+ Stopped vim /etc/hosts
$ fg
vim /etc/hosts
Explanation: When you press Ctrl+Z while in vim, the process is suspended and sent to the background. The fg command brings it back to the foreground, allowing you to continue editing.
Managing multiple background jobs:
$ sleep 300 &
[1] 12345
$ sleep 400 &
[2] 12346
$ sleep 500 &
[3] 12347
$ jobs
[1] Running sleep 300 &
[2]- Running sleep 400 &
[3]+ Running sleep 500 &
$ fg %2
sleep 400
Explanation: When you have multiple background jobs, you can bring a specific one to the foreground using its job number. Here, fg %2 brings job 2 (sleep 400) to the foreground.
Bringing job to foreground by command name:
$ vim config.txt &
[1] 12350
$ nano readme.md &
[2] 12351
$ emacs notes.org &
[3] 12352
$ jobs
[1] Running vim config.txt &
[2]- Running nano readme.md &
[3]+ Running emacs notes.org &
$ fg %vim
vim config.txt
Explanation: Instead of remembering job numbers, you can use the beginning of the command name. fg %vim brings the vim process to the foreground.
Using special job markers:
$ tar -czf backup.tar.gz /home/user/documents/ &
[1] 12400
$ rsync -av /source/ /dest/ &
[2] 12401
$ jobs
[1]- Running tar -czf backup.tar.gz /home/user/documents/ &
[2]+ Running rsync -av /source/ /dest/ &
# Bring current job (most recent) to foreground
$ fg
rsync -av /source/ /dest/
# Press Ctrl+Z to suspend
[2]+ Stopped rsync -av /source/ /dest/
# Bring previous job to foreground
$ fg %-
tar -czf backup.tar.gz /home/user/documents/
Explanation: The %% or %+ always refers to the current job, while %- refers to the previous job. Using just fg is equivalent to fg %%.
Using substring matching to find jobs:
$ find /var/log -name "*.log" -type f &
[1] 12450
$ grep -r "error" /var/log/ &
[2] 12451
$ find /home -name "*.pdf" -type f &
[3] 12452
$ jobs
[1] Running find /var/log -name "*.log" -type f &
[2]- Running grep -r "error" /var/log/ &
[3]+ Running find /home -name "*.pdf" -type f &
# Bring job containing "grep" to foreground
$ fg %?grep
grep -r "error" /var/log/
Explanation: The %?string format searches for any job whose command line contains the specified string, not just at the beginning.
Managing database operations and log monitoring:
$ mysql -u admin -p database_name
# Working in MySQL...
# Press Ctrl+Z
[1]+ Stopped mysql -u admin -p database_name
$ tail -f /var/log/mysql/error.log
# Monitoring logs...
# Press Ctrl+Z
[2]+ Stopped tail -f /var/log/mysql/error.log
$ jobs
[1]- Stopped mysql -u admin -p database_name
[2]+ Stopped tail -f /var/log/mysql/error.log
# Go back to MySQL session
$ fg %mysql
mysql -u admin -p database_name
# After executing query, suspend again
# Then check logs
$ fg %tail
tail -f /var/log/mysql/error.log
Explanation: This demonstrates a common workflow where you need to switch between an active database session and monitoring logs. Using fg allows seamless context switching without closing and reopening connections.
Managing build processes:
$ make all > build.log 2>&1
# Press Ctrl+Z after starting
[1]+ Stopped make all > build.log 2>&1
# Let it run in background
$ bg
[1]+ make all > build.log 2>&1 &
# Do other work...
$ vim source.c
# Check if build is still running
$ jobs
[1]+ Running make all > build.log 2>&1 &
# Bring build to foreground to watch progress
$ fg
make all > build.log 2>&1
Compiling module1.c...
Compiling module2.c...
Explanation: This shows the workflow of starting a long compilation, sending it to background with bg, doing other work, then bringing it back to foreground with fg to monitor progress.
> build.log 2>&1 ensures all output goes to the log file whether the job is in foreground or background.
Managing multiple SSH connections:
$ ssh user@server1.example.com
# Working on server1...
# Press Ctrl+Z
[1]+ Stopped ssh user@server1.example.com
$ ssh user@server2.example.com
# Working on server2...
# Press Ctrl+Z
[2]+ Stopped ssh user@server2.example.com
$ jobs
[1]- Stopped ssh user@server1.example.com
[2]+ Stopped ssh user@server2.example.com
# Return to server1
$ fg %server1
ssh user@server1.example.com
# After work, suspend and go to server2
$ fg %server2
ssh user@server2.example.com
Explanation: This demonstrates managing multiple SSH sessions using job control. You can quickly switch between different servers without closing connections.
screen or tmux for more robust session management.
Managing monitoring scripts and system checks:
$ ./monitor-disk-usage.sh
Checking disk usage...
# Press Ctrl+Z
[1]+ Stopped ./monitor-disk-usage.sh
$ ./check-network-latency.sh &
[2] 12500
$ ./analyze-logs.sh &
[3] 12501
$ jobs
[1]+ Stopped ./monitor-disk-usage.sh
[2]- Running ./check-network-latency.sh &
[3] Running ./analyze-logs.sh &
# Bring disk monitor back to see real-time output
$ fg %1
./monitor-disk-usage.sh
/dev/sda1: 75% used
/dev/sdb1: 45% used
# After checking, send to background
# Press Ctrl+Z, then:
$ bg
[1]+ ./monitor-disk-usage.sh &
# Bring network check to foreground to see results
$ fg %network
./check-network-latency.sh
Average latency: 45ms
Explanation: This shows how to manage multiple monitoring scripts, bringing them to foreground when you need to see their output in real-time, then continuing in background.
Dealing with jobs that encounter errors:
$ find / -name "config.xml" 2>/dev/null
# Many results scrolling by...
# Press Ctrl+Z
[1]+ Stopped find / -name "config.xml" 2>/dev/null
$ jobs
[1]+ Stopped find / -name "config.xml" 2>/dev/null
# Realize we need to capture output
$ fg
find / -name "config.xml" 2>/dev/null
# Press Ctrl+Z immediately
[1]+ Stopped find / -name "config.xml" 2>/dev/null
# Start a new one with proper redirection
$ find / -name "config.xml" 2>/dev/null > found_configs.txt &
[2] 12600
# Kill the old stopped job
$ kill %1
[1]+ Stopped find / -name "config.xml" 2>/dev/null
$ jobs
[2]+ Running find / -name "config.xml" 2>/dev/null > found_configs.txt &
Explanation: Sometimes you start a job and realize you need different output handling. This shows how to suspend the job, start a corrected version, and clean up the original.
kill %jobnumber to terminate stopped jobs that you no longer need.
| Command | Description | Usage |
|---|---|---|
bg |
Resume stopped job in background | bg %1 |
jobs |
List all jobs | jobs -l |
Ctrl+Z |
Suspend current foreground job | Key combination |
Ctrl+C |
Terminate current foreground job | Key combination |
kill |
Send signal to job | kill %1 |
disown |
Remove job from job table | disown %1 |
& |
Start command in background | command & |
jobs frequently to see what processes are stopped or running in backgroundnohup, screen, or tmux instead of job controlfg is a shell builtin and behaves slightly differently across shells:
nohup or disown# Start multiple jobs
$ long_running_task1 &
$ long_running_task2 &
$ long_running_task3 &
# Check all jobs
$ jobs -l
# Bring one to foreground, check it, send back
$ fg %1
# Press Ctrl+Z
$ bg
# Continue all stopped jobs in background
$ for job in $(jobs -p); do bg $job; done
#!/bin/bash
# Example: Managing parallel tasks
task1() { sleep 10; echo "Task 1 complete"; }
task2() { sleep 15; echo "Task 2 complete"; }
task3() { sleep 20; echo "Task 3 complete"; }
# Start all in background
task1 &
task2 &
task3 &
# Wait for all to complete
wait
echo "All tasks finished"
Solution: This means there are no jobs in the job table. Use jobs to verify.
Solution: The job number doesn't exist. The job may have completed or been killed. Run jobs to see available jobs.
Solution: The job may be waiting for input or stuck. Try Ctrl+C to terminate or Ctrl+Z to suspend and investigate.