On 6/3/25 7:41 AM, Grégory Pakosz wrote:
Hello all,

I'm using Bash 5.2 on macOS:
-----
bash-5.2$ bash -version
GNU bash, version 5.2.37(1)-release (aarch64-apple-darwin23.4.0)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-----

I reached out to #bash on Libera about the following little "loop.sh"
test program and they advised me to post to this list:

Thanks for the report. Job control really does make all the difference here.

-----
#!/usr/bin/env bash
# https://paste.debian.net/hidden/3e73a580/

_int() {
   printf '\nBEGIN TRAP\n'
   interrupted=true
   trap - INT
   printf 'END TRAP\n'
}

loop() {
   local interrupted=false
   trap _int INT

   printf 'BEFORE WHILE LOOP\ninterrupted: %s\n' "$interrupted"
   while ! "$interrupted"; do
     echo "interrupted: $interrupted"
     printf 'interrupted: %s\n' "$interrupted"
     sleep 0.5
   done
   printf 'AFTER WHILE LOOP\ninterrupted: %s\n' "$interrupted"
   "$interrupted" && kill -s INT -- "$$"
}

if [ -n "$BASH_VERSION" ] && [ "${BASH_SOURCE[0]}" = "$0" ]; then
   loop "$@"
fi

Chances are excellent that you're going to interrupt the `sleep', which
is an external program executed in a child process.

When job control is enabled, that child process is in its own process
group, separate from the shell's, and that process group is the one that
receives keyboard-generated signals like SIGINT (the foreground process
group).

When job control is not enabled, that child process runs in the same
process group as the shell, and that process group receives keyboard-
generated signals.

This is covered in the SIGNALS section of the manual page.

-----

• When I execute the loop.sh script, hitting CTRL+C ends up running
the _int() function:

You are running a non-interactive shell, job control is not enabled, the
shell receives the SIGINT, the shell runs the trap.

• When I source loop.sh then execute the loop() function, hitting
CTRL+C interrupts the script but the _int() function is not executed
which also means the trap for SIGINT is not cleared out:

You are running this with job control enabled, the shell doesn't receive
the SIGINT, the shell notices that `sleep' exited due to SIGINT and
interrupts the `source' (since that is what most people want -- bash
behaves more like a non-interactive shell when it's reading input from
a different source).

• When I disable job control and launch the loop() function again, it
behaves the same as when I execute the script:

Because the foreground process group receives the SIGINT, and the shell
is in that process group.

How does job control affect whether traps are being executed?

Because job control affects which process group is the foreground process
group and receives signals.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    c...@case.edu    http://tiswww.cwru.edu/~chet/

Reply via email to