Linux Command Reference

nohup

Synopsis

nohup COMMAND [ARG]... nohup OPTION

Description

The nohup command (no hangup) runs the specified command immune to hangup signals, with output redirected to a file. This allows processes to continue running even after you log out or close your terminal session. By default, both standard output and standard error are redirected to nohup.out in the current directory (or in the user's home directory if the current directory is not writable).

This is essential for running long-duration processes on remote servers where network interruptions or accidental disconnections would otherwise terminate the process. Unlike background jobs started with & alone, nohup-protected processes survive terminal closure because they ignore the SIGHUP (hangup) signal that the shell sends to its child processes upon termination.

Key Concepts

Detailed Examples

Example 1

Basic nohup Usage with Background Process

Run a long-duration script in the background, immune to hangups. This is the most common usage pattern for nohup, combining it with the background operator (&) to regain control of the terminal immediately.
# Run a script that will continue after logout nohup ./long_running_backup.sh & # The output shows the job number and PID # [1] 12345
Output:
[1] 12345 nohup: ignoring input and appending output to 'nohup.out'
Note:

The process ID (12345) is displayed, allowing you to monitor or kill the process later. All output will be written to nohup.out in the current directory. You can now safely log out and the backup will continue.

Example 2

Redirect Output to Custom File

Instead of using the default nohup.out file, redirect output to a named log file. This makes it easier to identify and review output from specific processes, especially when running multiple nohup commands.
# Redirect output to a specific file nohup python data_analysis.py > analysis.log 2>&1 & # Check the job status jobs -l # Monitor the output in real-time tail -f analysis.log
Output:
[1] 23456 nohup: ignoring input and redirecting stderr to stdout # jobs -l output: [1]+ 23456 Running nohup python data_analysis.py > analysis.log 2>&1 & # tail -f shows live output from the script
Note:

The syntax 2>&1 redirects standard error (file descriptor 2) to standard output (file descriptor 1), so both streams go to the same file. This is crucial for capturing error messages.

Example 3

Run Database Maintenance Without nohup.out

Sometimes you don't need to keep the output at all, or you want to completely suppress it. This example redirects all output to /dev/null, useful for scheduled maintenance tasks where logging is handled internally.
# Run without creating any output file nohup /usr/local/bin/database_maintenance.sh > /dev/null 2>&1 & # Store the PID for later reference echo $! > /var/run/db_maintenance.pid # Check if process is running ps -p $(cat /var/run/db_maintenance.pid)
Output:
[1] 34567 # PID stored in file for tracking # ps output shows process is running: PID TTY TIME CMD 34567 ? 00:00:12 database_mainte
Note:

The special variable $! contains the PID of the last background process. Storing it in a file allows system monitoring tools or other scripts to track the process.

Example 4

Run Multiple Commands with nohup

Execute multiple commands in sequence under nohup protection. This is useful for complex workflows where several steps must complete sequentially, and the entire process should survive terminal disconnection.
# Use a subshell to run multiple commands nohup bash -c 'echo "Starting process"; ./step1_download.sh; ./step2_process.sh; ./step3_upload.sh; echo "Process complete"' > pipeline.log 2>&1 & # Alternative: Use a wrapper script cat > run_pipeline.sh << 'EOF' #!/bin/bash echo "Pipeline started at $(date)" ./step1_download.sh ./step2_process.sh ./step3_upload.sh echo "Pipeline completed at $(date)" EOF chmod +x run_pipeline.sh nohup ./run_pipeline.sh > pipeline.log 2>&1 &
Output:
[1] 45678 # In pipeline.log: Starting process Pipeline started at Sun Dec 14 12:30:45 EST 2025 [output from step1...] [output from step2...] [output from step3...] Pipeline completed at Sun Dec 14 15:22:11 EST 2025 Process complete
Note:

Using bash -c allows you to run multiple commands, but creating a separate script is often cleaner for complex pipelines. Both approaches work with nohup.

Example 5

Monitor nohup Process Progress

After starting a nohup process, you often want to monitor its progress without interrupting it. This example shows various ways to check status, view output, and verify the process is still running.
# Start a long-running process nohup ./video_encoder.sh input.mp4 output.mp4 > encoding.log 2>&1 & PID=$! echo "Started encoding with PID: $PID" # Check if process is still running if ps -p $PID > /dev/null; then echo "Process is running" else echo "Process has finished or died" fi # View the last 20 lines of output tail -20 encoding.log # Follow the output in real-time (Ctrl+C to stop viewing) tail -f encoding.log # Check process resource usage ps -p $PID -o pid,pcpu,pmem,etime,cmd # Get more detailed information top -p $PID -n 1
Output:
Started encoding with PID: 56789 Process is running # tail -20 shows recent output lines # tail -f shows live streaming output # ps output: PID %CPU %MEM ELAPSED CMD 56789 95.3 2.1 00:15:42 ./video_encoder.sh input.mp4 output.mp4
Note:

The tail -f command is invaluable for monitoring nohup processes. Press Ctrl+C to stop viewing without killing the background process. The ELAPSED column in ps shows how long the process has been running.

Example 6

Run Java Application with nohup

Start a Java application server with nohup, ensuring it continues running after SSH disconnection. This is a common pattern for running web services, application servers, or long-running Java batch jobs.
# Run Java application with specific memory settings nohup java -Xmx2048m -Xms1024m \ -jar /opt/myapp/application.jar \ --spring.profiles.active=production \ > /var/log/myapp/app.log 2>&1 & # Save the PID echo $! > /var/run/myapp.pid # Create a status check script cat > check_app.sh << 'EOF' #!/bin/bash PID_FILE="/var/run/myapp.pid" if [ -f "$PID_FILE" ]; then PID=$(cat "$PID_FILE") if ps -p $PID > /dev/null 2>&1; then echo "Application is running (PID: $PID)" # Check if listening on expected port if netstat -tuln | grep -q ":8080"; then echo "Port 8080 is active" else echo "WARNING: Port 8080 not active" fi else echo "Application is NOT running" fi else echo "PID file not found" fi EOF chmod +x check_app.sh ./check_app.sh
Output:
[1] 67890 # check_app.sh output: Application is running (PID: 67890) Port 8080 is active # In /var/log/myapp/app.log: 2025-12-14 12:45:23.456 INFO Starting ApplicationMain 2025-12-14 12:45:25.123 INFO Tomcat started on port(s): 8080 (http) 2025-12-14 12:45:25.234 INFO Started ApplicationMain in 2.1 seconds
Warning:

For production Java applications, consider using systemd service files or dedicated process managers like supervisord instead of nohup. They provide better control, automatic restarts, and easier management.

Example 7

Schedule with cron and nohup

While cron jobs themselves are immune to hangups, using nohup in cron jobs can provide additional output management and ensure proper signal handling for complex scripts. This example shows best practices for combining cron and nohup.
# Add to crontab (crontab -e) # Run nightly backup at 2 AM 0 2 * * * /usr/bin/nohup /opt/scripts/nightly_backup.sh > /var/log/backups/backup_$(date +\%Y\%m\%d).log 2>&1 # More complex cron with email notification 0 3 * * * /usr/bin/nohup /opt/scripts/data_sync.sh > /tmp/sync_$(date +\%Y\%m\%d_\%H\%M).log 2>&1 && echo "Sync completed" | mail -s "Data Sync Success" admin@example.com || echo "Sync failed - check logs" | mail -s "Data Sync FAILURE" admin@example.com # Create a cron wrapper script for better control cat > /opt/scripts/cron_wrapper.sh << 'EOF' #!/bin/bash SCRIPT="$1" LOG_DIR="/var/log/cron_jobs" TIMESTAMP=$(date +%Y%m%d_%H%M%S) SCRIPT_NAME=$(basename "$SCRIPT" .sh) LOG_FILE="$LOG_DIR/${SCRIPT_NAME}_${TIMESTAMP}.log" mkdir -p "$LOG_DIR" echo "Starting $SCRIPT at $(date)" > "$LOG_FILE" nohup "$SCRIPT" >> "$LOG_FILE" 2>&1 EXIT_CODE=$? echo "Finished $SCRIPT at $(date) with exit code $EXIT_CODE" >> "$LOG_FILE" # Rotate old logs (keep last 30 days) find "$LOG_DIR" -name "${SCRIPT_NAME}_*.log" -mtime +30 -delete exit $EXIT_CODE EOF chmod +x /opt/scripts/cron_wrapper.sh # Use in crontab 0 4 * * * /opt/scripts/cron_wrapper.sh /opt/scripts/important_task.sh
Sample Log Output:
# In /var/log/cron_jobs/important_task_20251214_040000.log: Starting /opt/scripts/important_task.sh at Sun Dec 14 04:00:00 EST 2025 [task output here...] Finished /opt/scripts/important_task.sh at Sun Dec 14 04:23:45 EST 2025 with exit code 0
Note:

While nohup in cron is often redundant (cron jobs already don't receive SIGHUP), it's useful for output redirection and when scripts themselves spawn long-running child processes.

Example 8

nohup with Input Redirection

Run a program that expects input from a file rather than interactive input. Since nohup closes stdin by default, you need to explicitly redirect input if your program requires it.
# Create input file cat > input_data.txt << EOF command1 command2 command3 EOF # Run program with input from file nohup ./batch_processor < input_data.txt > results.log 2>&1 & # Alternative: Use here-document for small inputs nohup ./config_updater > update.log 2>&1 << EOF & option1=value1 option2=value2 option3=value3 EOF # For interactive programs that need input, use expect or similar cat > auto_install.exp << 'EOF' #!/usr/bin/expect -f set timeout -1 spawn /usr/local/bin/installer.sh expect "Enter installation directory:" send "/opt/myapp\r" expect "Proceed with installation? (y/n)" send "y\r" expect eof EOF chmod +x auto_install.exp nohup ./auto_install.exp > install.log 2>&1 &
Output:
[1] 78901 # In results.log: Processing command1... Processing command2... Processing command3... Batch processing complete # For expect script: Installation directory set to /opt/myapp Proceeding with installation... Installation completed successfully
Note:

nohup automatically redirects stdin from /dev/null, so any program requiring interactive input will fail. Use input redirection from files, or tools like expect for interactive programs.

Example 9

Gracefully Stop nohup Process

Properly terminate a nohup process using various signals. Unlike Ctrl+C (which doesn't work for background processes), you need to use kill commands with the appropriate PID.
# Start a process and save PID nohup ./long_service.sh > service.log 2>&1 & SERVICE_PID=$! echo $SERVICE_PID > service.pid echo "Service started with PID: $SERVICE_PID" # Later, to gracefully stop (allows cleanup): # Send SIGTERM (default kill signal) kill $(cat service.pid) # Wait a few seconds for graceful shutdown sleep 5 # Check if it's still running if ps -p $(cat service.pid) > /dev/null 2>&1; then echo "Process still running, forcing termination" # Send SIGKILL (force kill) kill -9 $(cat service.pid) else echo "Process terminated gracefully" fi # Clean up PID file rm -f service.pid # More sophisticated stop script cat > stop_service.sh << 'EOF' #!/bin/bash PID_FILE="service.pid" TIMEOUT=30 if [ ! -f "$PID_FILE" ]; then echo "PID file not found" exit 1 fi PID=$(cat "$PID_FILE") if ! ps -p $PID > /dev/null 2>&1; then echo "Process not running" rm -f "$PID_FILE" exit 0 fi echo "Sending SIGTERM to PID $PID" kill $PID # Wait for graceful shutdown ELAPSED=0 while ps -p $PID > /dev/null 2>&1; do sleep 1 ELAPSED=$((ELAPSED + 1)) if [ $ELAPSED -ge $TIMEOUT ]; then echo "Timeout reached, forcing termination" kill -9 $PID break fi if [ $((ELAPSED % 5)) -eq 0 ]; then echo "Waiting for shutdown... ($ELAPSED seconds)" fi done echo "Process terminated" rm -f "$PID_FILE" EOF chmod +x stop_service.sh
Output:
Service started with PID: 89012 # When stopping: Sending SIGTERM to PID 89012 Waiting for shutdown... (5 seconds) Waiting for shutdown... (10 seconds) Process terminated
Warning:

Always try SIGTERM (kill) before SIGKILL (kill -9). SIGTERM allows the process to clean up resources, close files properly, and exit gracefully. SIGKILL terminates immediately without cleanup.

Example 10

Complete Production Deployment Script

A comprehensive example showing best practices for using nohup in production: proper logging, PID management, status checking, and graceful shutdown. This serves as a template for production service management.
#!/bin/bash # File: service_manager.sh # Manages a nohup-based service with proper logging and control SERVICE_NAME="data_processor" SERVICE_CMD="/opt/apps/data_processor/run.sh" PID_FILE="/var/run/${SERVICE_NAME}.pid" LOG_DIR="/var/log/${SERVICE_NAME}" LOG_FILE="${LOG_DIR}/${SERVICE_NAME}_$(date +%Y%m%d).log" # Ensure log directory exists mkdir -p "$LOG_DIR" start_service() { if [ -f "$PID_FILE" ]; then PID=$(cat "$PID_FILE") if ps -p $PID > /dev/null 2>&1; then echo "Service already running with PID $PID" return 1 else echo "Removing stale PID file" rm -f "$PID_FILE" fi fi echo "Starting $SERVICE_NAME..." echo "$(date): Starting service" >> "$LOG_FILE" nohup $SERVICE_CMD >> "$LOG_FILE" 2>&1 & PID=$! echo $PID > "$PID_FILE" # Verify it started successfully sleep 2 if ps -p $PID > /dev/null 2>&1; then echo "Service started successfully with PID $PID" echo "Log file: $LOG_FILE" return 0 else echo "Service failed to start - check $LOG_FILE" rm -f "$PID_FILE" return 1 fi } stop_service() { if [ ! -f "$PID_FILE" ]; then echo "Service not running (no PID file)" return 0 fi PID=$(cat "$PID_FILE") if ! ps -p $PID > /dev/null 2>&1; then echo "Service not running (stale PID file)" rm -f "$PID_FILE" return 0 fi echo "Stopping $SERVICE_NAME (PID: $PID)..." echo "$(date): Stopping service" >> "$LOG_FILE" kill $PID # Wait up to 30 seconds for graceful shutdown TIMEOUT=30 ELAPSED=0 while ps -p $PID > /dev/null 2>&1; do sleep 1 ELAPSED=$((ELAPSED + 1)) if [ $ELAPSED -ge $TIMEOUT ]; then echo "Timeout - forcing termination" kill -9 $PID break fi done rm -f "$PID_FILE" echo "Service stopped" echo "$(date): Service stopped" >> "$LOG_FILE" return 0 } status_service() { if [ ! -f "$PID_FILE" ]; then echo "$SERVICE_NAME is NOT running" return 1 fi PID=$(cat "$PID_FILE") if ps -p $PID > /dev/null 2>&1; then echo "$SERVICE_NAME is running (PID: $PID)" echo "Uptime: $(ps -p $PID -o etime= | tr -d ' ')" echo "Memory: $(ps -p $PID -o rss= | awk '{printf "%.1f MB", $1/1024}')" echo "CPU: $(ps -p $PID -o %cpu=)%" echo "Log file: $LOG_FILE" # Show last 5 log lines echo -e "\nRecent log entries:" tail -5 "$LOG_FILE" return 0 else echo "$SERVICE_NAME is NOT running (stale PID file)" rm -f "$PID_FILE" return 1 fi } restart_service() { echo "Restarting $SERVICE_NAME..." stop_service sleep 2 start_service } tail_logs() { if [ -f "$LOG_FILE" ]; then echo "Following log file (Ctrl+C to stop):" tail -f "$LOG_FILE" else echo "Log file not found: $LOG_FILE" return 1 fi } # Rotate logs older than 7 days rotate_logs() { echo "Rotating old log files..." find "$LOG_DIR" -name "${SERVICE_NAME}_*.log" -mtime +7 -delete echo "Log rotation complete" } # Main command dispatcher case "$1" in start) start_service ;; stop) stop_service ;; restart) restart_service ;; status) status_service ;; logs) tail_logs ;; rotate) rotate_logs ;; *) echo "Usage: $0 {start|stop|restart|status|logs|rotate}" exit 1 ;; esac exit $?
Usage Examples:
# Start the service $ ./service_manager.sh start Starting data_processor... Service started successfully with PID 12345 Log file: /var/log/data_processor/data_processor_20251214.log # Check status $ ./service_manager.sh status data_processor is running (PID: 12345) Uptime: 00:15:23 Memory: 145.2 MB CPU: 12.3% Log file: /var/log/data_processor/data_processor_20251214.log Recent log entries: 2025-12-14 13:00:01 Processing batch 1234 2025-12-14 13:00:15 Processing batch 1235 2025-12-14 13:00:29 Processing batch 1236 # Stop the service $ ./service_manager.sh stop Stopping data_processor (PID: 12345)... Service stopped
Note:

This production-ready script demonstrates best practices: PID file management, graceful shutdown with timeout, status reporting, log rotation, and proper error handling. Use this as a template for managing nohup-based services.

Tips & Best Practices

Always Combine with Background Operator
Almost always use nohup command & together. Using nohup without & means the command runs in the foreground and you can't use your terminal. The & backgrounds the process and returns control immediately.
Redirect Both stdout and stderr
Use nohup command > file.log 2>&1 & to capture both standard output and error messages in the same file. The 2>&1 syntax is crucial for debugging as it captures error messages that would otherwise be lost.
Save and Track PIDs
Always save the process ID: nohup command &; echo $! > command.pid. This allows you to monitor, manage, or terminate the process later. Without the PID, finding and controlling your process becomes much harder.
Consider Modern Alternatives
For production services, consider using systemd, supervisord, or screen/tmux instead of nohup. These provide better process management, automatic restarts, logging integration, and easier monitoring. nohup is great for quick tasks but not ideal for complex service management.
Check File Write Permissions
Before running nohup, ensure you have write permission in the directory where nohup.out will be created. If the current directory isn't writable, nohup tries to create nohup.out in your home directory, which can lead to confusion about where output went.
Use Absolute Paths
When running scripts with nohup, use absolute paths for both the script and any files it references. Your working directory may not be what you expect, especially if the script is called from cron or other automated systems.
Monitor Disk Space for Logs
Long-running nohup processes can generate very large log files. Implement log rotation or regularly monitor disk usage to prevent filling up the filesystem. Consider using logrotate or similar tools for automatic log management.
Test Before Logging Out
After starting a nohup process, verify it's running correctly before disconnecting. Check the PID with ps, review the first few lines of output, and ensure the process is actually doing what you expect. It's frustrating to log out only to discover the process failed immediately.
Understand nohup vs disown
If you forgot to start a process with nohup, you can use disown -h %jobnum to remove it from the shell's job table and make it immune to SIGHUP. However, you'll need to manually handle output redirection. bg can move a stopped job to background before using disown.