trap INT in bash script fails when a function outputs its stdout in a process substitution call

260 Views Asked by At

I have the below script example to handle trap on EXIT and INT signals during some job, and trigger a clean up function that cannot be interrupted

#!/bin/bash

# Our main function to handle some job:
some_job() {
    echo "Working hard on some stuff..."
    for i in $(seq 1 5); do
        #printf "."
        printf '%s' "$i."
        sleep 1
    done

    echo ""
    echo "Job done, but we found some errors !"
    return 2 # to simulate script exit code 2
}

# Our clean temp files function
# - should not be interrupted
# - should not be called twice if interrupted
clean_tempfiles() {
    echo ""
    echo "Cleaning temp files, do not interrupt..."
    for i in $(seq 1 5); do
        printf "> "
        sleep 1
    done
    echo ""
}

# Called on signal EXIT, or indirectly on INT QUIT TERM
clean_exit() {
    # save the return code of the script
    err=$?

    # reset trap for all signals to not interrupt clean_tempfiles() on any next signal
    trap '' EXIT INT QUIT TERM

    clean_tempfiles
    exit $err # exit the script with saved $?
}

# Called on signals INT QUIT TERM
sig_cleanup() {
    # save error code (130 for SIGINT, 143 for SIGTERM, 131 for SIGQUIT)
    err=$?

    # some shells will call EXIT after the INT signal
    # causing EXIT trap to be executed, so we trap EXIT after INT
    trap '' EXIT 

    (exit $err) # execute in a subshell just to pass $? to clean_exit()
    clean_exit
}

trap clean_exit EXIT
trap sig_cleanup INT QUIT TERM

some_job

The trap works properly, clean_tempfiles() cannot be interrupted and the exit code from some_job() is preserved

Now, if I want to redirect the output from some_job() using process substitution, in the last script line:

# - redirect stdout and stderr to stdout_logfile
# - redirect stderr to stderr_logfile
# - redirect both stdout and stderr to terminal
some_job > >(tee -a stdout_logfile) 2> >(tee -a stderr_logfile | tee -a stdout_logfile >&2)

the normal EXIT trap is properly triggered. However, the SIGINT trap is never triggered. Ctr^C cannot be trapped as soon as the last logging line is added

I could workaround it using POSIX sh compliant redirects with temp log fifo pipes, however, I would really have it working with the simpler bash syntax using process substitution

Is this even possible ?

0

There are 0 best solutions below