2

I have a code that looks like this:

{
    trap cleanup SIGHUP SIGINT SIGTERM

    function executed() {
        if [ ${1} -ne 0 ]
        then
            echo "Failed!"
            cleanup
            exit 
        else
            echo "Succeeded!"
        fi
    }

    function cleanup() {
        echo "Cleaning up ..."
        # deleting some files and stuff like that
    }

    bunch of code ...
    ...

} 2>&1 | while IFS= read -r line; do echo "$(date) $line"; done \
>> ldapfe_graceful_$(date '+%Y_%m_%d__%H_%M_%S').log 

I can't paste all my code since I'm not sure about company policy on this and all that, but the most important parts are there.

I press Ctrl + c while this script is running and it either stops immediately, or I'm shown a little ^C and then it stops after 5-10 seconds, but the cleanup function is never called.

I've put all of the code inside {} to redirect it nicely in a file (I've used seperate script to call this one and do the redirecting but it seems harder to kill that one and propagate the signal to this one so I've just decided to put it all in curly braces here).

I'm sure I'm missing something regarding the curly braces because if I put trap and cleanup outside of the {} block the cleanup function is called, but other parts of the code should be able to call it too and it's not possible if it's outside of the {} braces.

EDIT: I've tried declaring trap after the cleanup function, but no change.

  • You're throwing away the error stream. Is there any errors reported? – Kusalananda Jun 30 '16 at 14:36
  • What do you mean by throwing away? Doesn't it redirect it along with stdout? Anyway, no errors are reported. – Luka Jun 30 '16 at 20:06
  • You are absolutely right! Sorry. Mea culpa. – Kusalananda Jun 30 '16 at 20:07
1
  1. Other parts of the code should be able to call the cleanup function regardless of it being inside or outside the {} braces, as long as it's declared before its actual call (actual, it's not about a former script line), and on the same or lower bash shell level ($BASH_SUBSHELL).

  2. (EDITED) The trap can be called if it was already declared and it has to be declared on the same or lower subshell level. Apparently, the signal is cascaded down, as the code below shows when you run it.

.

#!/usr/bin/env bash

trap "echo ok 0" 2

(
    echo subshell: $BASH_SUBSHELL   
    trap "echo ok 1" 2
    (
        echo subshell: $BASH_SUBSHELL   
        trap "echo ok 2" 2;
        sleep 100
        #now test the trap
    )
)

Result:

subshell: 0
subshell: 1
subshell: 2
^Cok 2
ok 1
ok 0

But not it the pipes:

#!/bin/bash

trap "echo ok 0" 2

{
echo $BASH_SUBSHELL
trap "echo ok 1" 2
} | \
    {
        trap "echo ok 2" 2
        read line; echo $line;
        sleep 100
        #now Ctrl-c
    }

Result:

1
^Cok 2
ok 0
  1. The braces construct an anonymous function. The function keeps the bash shell level, but not in all contexts.

Analyse the script below for illustration. Run it in a terminal and see what it produces.

#!/bin/bash

k=k
msg='echo line: $LINENO, \$k: $k, BASH_SUBSHELL: $BASH_SUBSHELL'

eval $msg

{
    k=a
    eval $msg
} &

sleep 1
#job %1 should be done by now
jobs
eval $msg

{
    k=b
    eval $msg
} | {
    read line; echo $line;
    eval $msg
}

eval $msg

{
    k=c
    eval $msg
}

eval $msg

{ trap 'echo -e "\nterminating"; exit;' 2;}

sleep 100 #try out the trap by hitting Ctrl-c
  1. The solution for your script is:

a. Move the trap before the first {.

b. Try to move cleanup function before the first { using some smart constructs like eval (see in my script how it works). If not possible try to build a proxy function in the braces to a more general one before them and patch what's missing in its call in the trap.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.