Get exit code of a background process

I have a command CMD called from my main bourne shell script that takes forever.

I want to modify the script as follows:

  • Run the command CMD in parallel as a background process ($CMD &).
  • In the main script, have a loop to monitor the spawned command every few seconds. The loop also echoes some messages to stdout indicating progress of the script.
  • Exit the loop when the spawned command terminates.
  • Capture and report the exit code of the spawned process.
  • Can someone give me pointers to accomplish this?


    1: In bash, $! holds the PID of the last background process that was executed. That will tell you what process to monitor, anyway.

    4: wait <n> waits until the process with ID is complete (it will block until the process completes, so you might not want to call this until you are sure the process is done). After wait returns, the exit code of the process is returned in the variable $?

    2, 3: ps or ps | grep " $! " ps | grep " $! " can tell you whether the process is still running. It is up to you how to understand the output and decide how close it is to finishing. ( ps | grep isn't idiot-proof. If you have time you can come up with a more robust way to tell whether the process is still running).

    Here's a skeleton script:

    # simulate a long process that will have an identifiable exit code
    (sleep 15 ; /bin/false) &
    my_pid=$!
    
    while   ps | grep " $my_pid "     # might also need  | grep -v grep  here
    do
        echo $my_pid is still in the ps output. Must still be running.
        sleep 3
    done
    
    echo Oh, it looks like the process is done.
    wait $my_pid
    my_status=$?
    echo The exit status of the process was $my_status
    

    当我有类似的需求时,我就是这样解决它的:

    # Some function that takes a long time to process
    longprocess() {
            # Sleep up to 14 seconds
            sleep $((RANDOM % 15))
            # Randomly exit with 0 or 1
            exit $((RANDOM % 2))
    }
    
    pids=""
    # Run five concurrent processes
    for i in {1..5}; do
            ( longprocess ) &
            # store PID of process
            pids+=" $!"
    done
    
    # Wait for all processes to finnish, will take max 14s
    for p in $pids; do
            if wait $p; then
                    echo "Process $p success"
            else
                    echo "Process $p fail"
            fi
    done
    

    As I see almost all answers use external utilities (mostly ps ) to poll the state of the background process. There is a more unixesh solution, catching the SIGCHLD signal. In the signal handler it has to be checked which child process was stopped. It can be done by kill -0 <PID> built-in (universal) or checking the existence of /proc/<PID> directory (Linux specific) or using the jobs built-in (bash specific. jobs -l also reports the pid. In this case the 3rd field of the output can be Stopped|Running|Done|Exit . ).

    Here is my example.

    The launched process is called loop.sh . It accepts -x or a number as an argument. For -x is exits with exit code 1. For a number it waits num*5 seconds. In every 5 seconds it prints its PID.

    The launcher process is called launch.sh :

    #!/bin/bash
    
    handle_chld() {
        local tmp=()
        for((i=0;i<${#pids[@]};++i)); do
            if [ ! -d /proc/${pids[i]} ]; then
                wait ${pids[i]}
                echo "Stopped ${pids[i]}; exit code: $?"
            else tmp+=(${pids[i]})
            fi
        done
        pids=(${tmp[@]})
    }
    
    set -o monitor
    trap "handle_chld" CHLD
    
    # Start background processes
    ./loop.sh 3 &
    pids+=($!)
    ./loop.sh 2 &
    pids+=($!)
    ./loop.sh -x &
    pids+=($!)
    
    # Wait until all background processes are stopped
    while [ ${#pids[@]} -gt 0 ]; do echo "WAITING FOR: ${pids[@]}"; sleep 2; done
    echo STOPPED
    

    For more explanation see: Starting a process from bash script failed

    链接地址: http://www.djcxy.com/p/97128.html

    上一篇: rsync退出消息“stdin不是tty”

    下一篇: 获取后台进程的退出代码