0

I have this code:

     for job in `jobs -p`; do
         code=0;
         wait ${job} || code=$?
         if [[ "${code}" != "0" ]]; then
            echo "At least one job failed with exit code => ${code}" ;
            exit 1;
         fi
     done

right after the line: echo "At least one job failed with exit code => ${CODE}" ;

I want to add a line that logs the command that failed, something like this:

     for job in `jobs -p`; do
         code=0;
         wait ${job} || code=$?
         if [[ "${code}" != "0" ]]; then
            echo "At least one job failed with exit code => ${code}" ;
            echo "The job that failed was $(ps -p ${job})"
            exit 1;
         fi
     done

not that a job is just the pid of the subprocess. The problem is that this line:

echo "The job that failed was $(ps -p ${job})"

doesn't really about anything - I need the actually command that was run, given the pid=job.

3 Answers 3

3

At the point you're running the ps command, the process already exited (you're handling its return code, right?)

Just change the logic so you run the ps command earlier in the script, before the wait and store that in a variable:

for job in $(jobs -p); do
    process_info=$(ps -p "${job}" -o args=)
    wait "${job}" || {
        code=$?
        echo "Job running [${process_info}] failed with exit code ${code}." >&2
        exit 1
    }
done
6
  • thanks, seems like the right idea, but not sure if this works on MacOS though, got something x-platform? Commented Mar 24, 2018 at 5:11
  • I don't see why it wouldn't...
    – filbranden
    Commented Mar 24, 2018 at 5:26
  • take a look at this: gist.github.com/ORESoftware/2f0444cadef5b3546fca0eec749b4b70 Commented Mar 24, 2018 at 5:28
  • I just get a blank line => $process_info is just empty...I tried a lot of things...nothing is working :( Commented Mar 24, 2018 at 5:28
  • @FilipeBrandenburger You can't do this either in case the jobs exit out of order. For example, if the last job in the output of jobs -p exits first.
    – Kusalananda
    Commented Mar 24, 2018 at 7:09
0

As pointed out, you can't use ps on a non-existing process.

If you have a bash that supports associative arrays:

declare -A jobinfo

# collect job information
joblist=( $(jobs -p) )
for pid in "${joblist[@]}"; do
    jobinfo["$pid"]="$( ps -p "$pid" -o args= )"
done

# later...

# wait for jobs
err=0
for pid in "${joblist[@]}"; do
    if ! { wait "$pid" || ! (( code=$? )); }; then
        printf 'Got non-zero exit status (%d) from PID %d: %s\n' \
            "$code" "$pid" "${jobinfo[$pid]}"
        err=1
    fi
done

# exit 0 if all was good, exit 1 otherwise
exit "$err"

Here I collect all the necessary data before starting to wait for jobs to exit. I also wait for all jobs to finish so that the user gets information about not just the first failing job.


Without using associative arrays (should work in the default bash on macOS):

# collect job information
joblist=( $(jobs -p) )
for pid in "${joblist[@]}"; do
    jobinfo+=( "$( ps -p "$pid" -o args= )" )
done

# later...

err=0
i=0
for pid in "${joblist[@]}"; do
    if ! { wait "$pid" || ! (( code=$? )); }; then
        printf 'Got non-zero exit status (%d) from PID %d: %s\n' \
            "$code" "$pid" "${jobinfo[$i]}"
        err=1
    fi

    i=$(( i + 1 ))
done

exit "$err"
0

If your OS (e.g. Linux) has a /proc directory, you can get every needed information from /proc/$PID

for PID in $(jobs -p); do
    dosomethingwith /proc/$PID/ # please take a look at what it contents ;-)
    done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .