fg - Foreground Job Control

Bring background jobs to the foreground

Command Overview

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.

Basic Syntax

fg [job_spec]

Where:

  • job_spec - Job identifier (optional): %n, %string, %?string, %%, %+, %-
  • If no job_spec is given, brings the current job to foreground

Job Specification Formats

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

Detailed Examples

Example 1

Basic Foreground Operation

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.

Tip: This is incredibly useful when you need to quickly check something in the shell while editing a file, then return to your editor.
Example 2

Bringing Specific Job by Number

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.

Note: The + symbol indicates the current job, and - indicates the previous job. These markers change as jobs are manipulated.
Example 3

Using Command Name to Select Job

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.

Tip: This is particularly useful when job numbers change frequently due to jobs completing.
Example 4

Working with Current and Previous Jobs

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 %%.

Example 5

Pattern Matching with Job Selection

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.

Note: This is useful when you can't remember the exact start of the command but know a distinctive word within it.
Example 6

Real-World Database Work Scenario

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.

Tip: This pattern works great for any scenario where you need to check output or logs while working in an interactive application.
Example 7

Long-Running Compilation Task

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.

Note: The output redirection > build.log 2>&1 ensures all output goes to the log file whether the job is in foreground or background.
Example 8

SSH Session Management

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.

Warning: Suspended SSH sessions may timeout depending on server configuration. Consider using screen or tmux for more robust session management.
Example 9

Monitoring Script Execution

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.

Example 10

Error Handling and Job Recovery

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.

Tip: You can use kill %jobnumber to terminate stopped jobs that you no longer need.

Related Commands and Workflow

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 &

Important Notes and Best Practices

Best Practices

  • Use jobs frequently to see what processes are stopped or running in background
  • For long-running tasks, consider using nohup, screen, or tmux instead of job control
  • Remember that job numbers are session-specific and reset when you close your shell
  • Use descriptive command names to make job identification easier
  • Stopped jobs consume resources; either continue them or kill them

Shell Compatibility

fg is a shell builtin and behaves slightly differently across shells:

  • bash/zsh: Full support for all job specification formats
  • sh/dash: Limited job control features
  • tcsh/csh: Similar functionality with slightly different syntax

Common Pitfalls

  • Session Termination: All jobs (stopped or backgrounded) are terminated when you logout unless you use nohup or disown
  • Terminal Output: Background jobs that produce output can mess up your terminal display
  • Input Requirements: Jobs requiring input must be in foreground; they'll stop if they need input while backgrounded
  • Job Numbering: Job numbers can change as jobs complete; use command name matching for reliability

Advanced Usage Patterns

Combining with Other Job Control

# 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

Script Integration

#!/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"

Troubleshooting

Problem: "fg: no current job"

Solution: This means there are no jobs in the job table. Use jobs to verify.

Problem: "fg: %2: no such job"

Solution: The job number doesn't exist. The job may have completed or been killed. Run jobs to see available jobs.

Problem: Job brought to foreground but seems frozen

Solution: The job may be waiting for input or stuck. Try Ctrl+C to terminate or Ctrl+Z to suspend and investigate.