2

I have following script

#!/bin/bash

exec 5> >(logger -t $0)
BASH_XTRACEFD="5"
set -x

trap _reboot INT

DIALOG_TITLE="This is fancy dialog title"

_reboot() {
        echo Exiting
        exit
}

dialog --title "${DIALOG_TITLE}" --yesno "Welcome to Dialog" 0 0

However when i do CTRL+C, script is exited without printing anything. If i remove either set -x or BASH_XTRACEFD="5" it will work fine and trap is caught and _reboot function is executed. But if i leave both in (which i need for debugging purposes) - then trap looses all meaning.

Exit code is 141 which is interesting when i exit with CTRL+C. If i let the script run it's natural course it will exit with 0 However if i remove either of set -x or BASH_XTRACEFD="5" and then CTRL+C i will exit with 55 then.

This for some reason happens only while dialog is on screen. For example if i do

while true; do
  sleep 5
done

And then exit with CTRL+C trap will be executed.

I need help figuring this thing out.

EDIT: Might be worth mentioning that bash version is 5.1.16, running on Alpine 3.16

5
  • dialog is a separate program with its own interrupt handlers. To see how that plays out when it is run from a shell script, try adding if [ "$?" = 141 ] ; then echo "Ctrl-C pressed in dialog"; else echo "Dialog exited normally"; fi immediately after the dialog line.
    – cas
    Jul 4, 2022 at 11:32
  • That will not work as when CTRL+C is pressed, entire script is terminated so next line will not be evaluated at all. Jul 4, 2022 at 11:45
  • not necessarily. if dialog is handling ^C itself (which is what the if statement is trying to confirm), the bash script won't see the INT signal (unless you press ^C multiple times).
    – cas
    Jul 4, 2022 at 12:00
  • BTW, in bash, exit code 141 is usually a result of bash getting a SIGPIPE signal (subtract 128 from exit codes above 128 to get the actual signal, 141-128=13=SIGPIPE, i.e. a pipe terminated unexpectedly. Also check the PIPESTATUS array). Your script doesn't seem to be piping anything, though.
    – cas
    Jul 4, 2022 at 12:09
  • But in my case, yes ,if i do ctrl+c it quits both dialog and script, but only in situation described in main message - when both set -x and BASH_XTRACEFD="5" are used together. Otherwise if either (or both) of them are removed, it will work as intended and script can trap the signal even when dialog is displayed. Jul 4, 2022 at 15:30

1 Answer 1

3

dialog uses ncurses, which captures SIGINT, as documented in the initscr manpage section on Signal Handlers:

SIGINT
The handler attempts to cleanup the screen on exit. Although it usually works as expected, there are limitations:

  • Walking the SCREEN list is unsafe, since all list management is done without any signal blocking.
  • On systems which have REENTRANT turned on, set_term uses functions which could deadlock or misbehave in other ways.
  • endwin calls other functions, many of which use stdio or other library functions which are clearly unsafe.

bash would only "see" the signal when the child process does not catch it first.

2
  • What's frustrating is that if i do ctrl+c, if dialog catches it first, bash should ignore it and proceed with other operations, right? Here it's not the case. Also ,this all works fine if i comment any of "set +x" or 'BASH_XTRACEFD="5"'. If i comment either one of them and do ctrl-c while the dialog window is displayed , the signal will be trapped by script just fine. For some reason when both are used together (set -x and BASH_XTRACEFD="5" ) it doesn't work Jul 4, 2022 at 15:28
  • 1
    That's probably something-like the trace-fd is attached via bash to the controlling terminal, and that child-processes generally aren't aware of it (though whether bash closes that file-descriptor when fork/exec or not could allow the child to interfere...). Jul 4, 2022 at 16:13

You must log in to answer this question.

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