LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Shell Scripting -- Trap Weirdness (https://www.linuxquestions.org/questions/programming-9/shell-scripting-trap-weirdness-594861/)

mudd1 10-26-2007 02:52 PM

Shell Scripting -- Trap Weirdness
 
Using bash 3.2.13 (I also tried 3.1.17) I found a strange behaviour using nested traps. The following script will demonstrate the problem:

Code:

#!/bin/bash

foo() {
    trap 'echo "foo trap triggered"; exit' 2
    trap
    echo 'foo read'
    read
    echo 'end of foo()'
}

while (true); do
    echo 'beginning of loop'
    trap 'echo "loop trap triggered"; foo; continue' 2
    echo 'loop read'
    read
    echo 'end of loop'
done

In my understanding, this should exit after pressing Ctrl-C twice: First Ctrl-C brings it to foo(), there Ctrl-C is reset to exit the script (which the trap command without parameters confirms). But as a matter of fact it never exits (you'll have to press Ctrl-Z and kill it). Actually I really have no idea what it does after the second Ctrl-C or where it stays after pressing Ctrl-C once and then enter once. It leaves foo() but only continues with the loop after a second enter that corresponds to no read as far as I understand it. I don't find anything in the Posix standard that could explain this behaviour.

Many thanks in advance,

Christian

PS: Yes, I actually do need this kind of structure. Could replace it with an ugly goto but bash doesn't support that either.

PPS: If you find all those echos hard to read or don't trust them, stripped down version following:
Code:

foo() {
    trap 'exit' 2
    read
}

while (true); do
    trap 'foo; continue' 2
    read
done


jailbait 10-26-2007 03:06 PM

Quote:

Originally Posted by mudd1 (Post 2938020)
In my understanding, this should exit after pressing Ctrl-C twice: First Ctrl-C brings it to foo(), there Ctrl-C is reset to exit the script (which the trap command without parameters confirms). But as a matter of fact it never exits (you'll have to press Ctrl-Z and kill it). Actually I really have no idea what it does after the second Ctrl-C or where it stays after pressing Ctrl-C once and then enter once. It leaves foo() but only continues with the loop after a second enter that corresponds to no read as far as I understand it. I don't find anything in the Posix standard that could explain this behaviour.

I think that you are making the basic assumption that traps are nested. I have used traps in my own code and my understanding is (and the way my code works is) that each trap replaces the previous trap. Thus at any time only one trap exists for SIGSPEC 2. When you press Ctrl-C you take the trap exit and you no longer have a trap exit for Ctrl-C. Subsequent presses on Ctrl-C are ignored unless you enter a new trap command for SIGSPEC 2.

------------------
Steve Stites

mudd1 10-26-2007 03:10 PM

Quote:

Originally Posted by jailbait (Post 2938040)
I think that you are making the basic assumption that traps are nested. I have used traps in my own code and my understanding is (and the way my code works is) that each trap replaces the previous trap. Thus at any time only one trap exists for SIGSPEC 2. When you press Ctrl-C you take the trap exit and you no longer have a trap exit for Ctrl-C. Subsequent presses on Ctrl-C are ignored unless you enter a new trap command for SIGSPEC 2.

But shouldn't the exit command in the second trap already exit the script (and not only the function, which it apparently doesn't do either BTW)? And if it doesn't how do I exit the script no matter where I am?

PS: BTW, I don't want those traps to behave as if they were nested (whatever that means anyway). I'm just assuming that there is such a thing because the second trap which is set before the first one has finished its commands behaves differently (i.e. not at all).

jailbait 10-26-2007 03:31 PM

"PS: BTW, I don't want those traps to behave as if they were nested (whatever that means anyway). I'm just assuming that there is such a thing because the second trap which is set before the first one has finished its commands behaves differently (i.e. not at all)."

Nesting means that the kernel keeps a pushdown list of traps. When the latest trap is executed then it is removed and the next youngest trap becomes operative. Nesting does not happen for the trap command. When you issue a trap for a particular SIGSPEC then any previous trap for that SIGSPEC ceases to exist. So only the latest trap command is ever operative in your program.

"But shouldn't the exit command in the second trap already exit the script (and not only the function, which it apparently doesn't do either BTW)?"

No the second trap command does not contain any command argument.

"And if it doesn't how do I exit the script no matter where I am?"

Use the exit command as the ARG parameter in the trap command that is currently valid. See:

man trap

--------------------
Steve Stites

mudd1 10-26-2007 06:04 PM

Quote:

Originally Posted by jailbait (Post 2938070)
"But shouldn't the exit command in the second trap already exit the script (and not only the function, which it apparently doesn't do either BTW)?"

No the second trap command does not contain any command argument.

"And if it doesn't how do I exit the script no matter where I am?"

Use the exit command as the ARG parameter in the trap command that is currently valid. See:

man trap

Whoa, there's really no need to RTFM me.
With "second trap" I mean the second one that gets called, not the second one to appear in the code. Sorry for not being exact on this matter. So let me rephrase my question: Shouldn't the exit command in the
Code:

trap 'exit' 2
line already exit the script by the second press of Ctrl-C?

And what do you mean there's no ARG parameter? Calling trap without any parameters just outputs the current signal command mapping. It's there for debugging purposes only which is why I omitted it in the second version of the script. If that's what you meant then unfortunately that won't resolve the issue.

jailbait 10-27-2007 12:25 PM

Quote:

Originally Posted by mudd1 (Post 2938177)
So let me rephrase my question: Shouldn't the exit command in the
Code:

trap 'exit' 2
line already exit the script by the second press of Ctrl-C?

trap "exit" 2

will exit the code on the first press of Ctrl-C.

------------------
Steve Stites

mudd1 10-28-2007 02:55 AM

Quote:

Originally Posted by jailbait (Post 2938857)
trap "exit" 2

will exit the code on the first press of Ctrl-C.

Sure, but the line isn't executed until after the first press of Ctrl-C so globally it's the second one. Or what am I missing?

DrkShad0w 11-04-2007 10:19 PM

Code:

function trap1 {
  echo "Trap1"
  trap "trap2" SIGINT
  sleep 10
}

function trap2 {
  echo "Trap2"
  trap "exit 1" SIGINT
  sleep 10
}

echo "Start"
trap "trap1" SIGINT
sleep 10

when running this code:

Code:

$ traptest.sh_
Start
<ctrl-C>
Trap1
<ctrl-C>
$ _

You can see that you can't set a trap from within a trap. Now... WHY?!? It would be so convenient.

On the other hand, if things are changed somewhat...

Code:

function trap1 {
  echo "Trap1"
  trap "trap2" SIGINT
  sleep 10
  [ $? -ne 0 ] && trap2
}

function trap2 {
  echo "Trap2"
  trap "exit 1" SIGINT
  sleep 10
}

echo "Start"
trap "trap1" SIGINT

sleep 10

and executed...

Code:

$ traptest.sh_
Start
<ctrl-C>
Trap1
<ctrl-C>
Trap2
<ctrl-C>
$ _

Here, you might expect that trap2's trap takes effect.. but I don't think it would.

A third test script.. to test the viability of using the return code always:

Code:

function trap1 {
  echo "Trap1"
  trap "trap2" SIGINT
  sleep 10
  [ $? -ne 0 ] && trap2
}

function trap2 {
  echo "Trap2"
  trap "exit 1" SIGINT
  sleep 10
}

echo "Start"
#trap "trap1" SIGINT

sleep 10
[ $? -ne 0 ] && trap1

When executed:

Code:

$ traptest.sh
Start
$ _

Arright, this scores a 'Windows' in lameness. Only in traps will the return code not be zero if a command is ctrl-c'd. If we're not within a trap, the shell itself will execute. If we're in a `read` inside a trap, ctrl-c won't affect anything and we'll have to hit "enter" to get out of the read. If we're not in a trap and we're read'ing, hitting ctrl-c will exit the shell and everything will stop. If I do a `read` from the command line, ctrl-c will kill it. I dunno what's happening there. I suppose I never honestly felt that linux was consistent.

Again.. this has a score of 'Windows' in lameness. Still, for my particular script, I now know I can check the return code of `cat <named pipe>` to see if it had any data to read. At least, I think I can.

Hope this clears up something.

-DrkShadow

mudd1 11-05-2007 02:36 AM

That was very enlightening indeed. Not good news, but illuminative :) As the Posix standard doesn't seem to regulate this behaviour, do you think a bug report might help?

bigearsbilly 11-05-2007 05:03 AM

I've done loads of stuff with traps in the past.
They are awkward and not to be trusted.

You can never ever get really fine control or robust exception handling
in a sh, bash, or ksh script. I've tried and tried.

I keep away from them now if i can help it.


All times are GMT -5. The time now is 07:36 PM.