How to Get the PID of a Newly Started Process in Linux/Unix


3 views

When working with process management in Unix-like systems, developers often need to launch a background process and obtain its Process ID (PID) for later control. The naive approach using ps with grep/awk filtering has significant limitations:

# Problematic approach
myCommand &
ps aux | grep 'myCommand' | awk '{print $2}'

This method fails because:

  • Process names aren't guaranteed to be unique
  • Race conditions may occur between process start and ps execution
  • The grep command might match itself or other unrelated processes

The shell provides a built-in way to get the PID of the most recently started background process through the special variable $!:

# Correct approach
myCommand &
pid=$!
echo "Process started with PID: $pid"

This method is:

  • Instantaneous (no race conditions)
  • Precise (always gets the correct PID)
  • Portable (works across different shells)
  • For more complex scenarios, consider these patterns:

    1. One-liner with immediate PID capture

    myCommand & pid=$!; echo "PID: $pid"
    

    2. Function wrapper for repeated use

    run_and_get_pid() {
        "$@" &
        echo $!
    }
    
    # Usage:
    pid=$(run_and_get_pid myCommand -with args)
    

    3. Process substitution with PID tracking

    exec 3< <(myCommand & echo $! >&3)
    read -u3 pid
    exec 3<&-
    
    • Don't forget the & to run in background
    • Store $! immediately after starting the process
    • Be aware that $! only works for background processes

    In rare cases where you can't use $!, consider:

    # Using pgrep with process arguments
    pgrep -f 'myCommand.*specific_arg'
    
    # Using custom temporary files
    myCommand &
    echo $! > /tmp/mypid.pid
    

    Remember that these alternatives have their own limitations and should only be used when absolutely necessary.


    When working with process management in Linux, one common challenge is reliably obtaining the Process ID (PID) of a command you've just executed. The naive approach of using ps with grep/awk often fails because:

    
    # Problematic approach
    myCommand &
    ps aux | grep myCommand | awk '{print $2}'
    

    This fails because:

    • Process names aren't always unique
    • The grep command might match itself
    • Race conditions can occur if the process terminates quickly

    Bash provides the perfect built-in solution with the $! special variable, which stores the PID of the last background process:

    
    # Correct way to get PID immediately
    myCommand &
    pid=$!
    echo "Process started with PID: $pid"
    

    This approach is:

    • Atomic - no race conditions
    • Precise - always gets the correct PID
    • Efficient - no external process calls needed

    For more complex scenarios, consider these patterns:

    
    # 1. One-liner version
    myCommand & pid=$!
    
    # 2. With process cleanup
    myCommand & pid=$!
    trap "kill $pid" EXIT
    
    # 3. In a function
    start_process() {
        "$@" &
        echo $!
    }
    

    In rare cases where you can't use $!, consider:

    
    # Using pgrep with start time filtering
    myCommand &
    pid=$(pgrep -n -f "myCommand")
    
    # Using procfs (Linux-specific)
    myCommand &
    pid=$(ls -ld /proc/[0-9]*/exe 2>/dev/null | 
          awk -F/ -v cmd=$(which myCommand) '$NF == cmd {print $3}' | 
          sort -n | tail -1)
    
    • Subshells: $! won't work across subshell boundaries
    • Quick processes: Very short-lived processes might exit before you can capture their PID
    • Multiple invocations: Be careful when starting multiple instances in quick succession