This is parent.sh:
#!/bin/bash trap 'exit' SIGHUP SIGINT SIGQUIT SIGTERM if ! [ -t 0 ]; then # if running non-interactively sleep 5 & # allow a little time for child to generate some output set -bm # to be able to trap SIGCHLD trap 'kill -SIGINT $$' SIGCHLD # when sleep is done, interrupt self automatically - cannot issue interrupt by keystroke since running non-interactively fi sudo ~/child.sh
This is child.sh:
#!/bin/bash test -f out.txt && rm out.txt for second in {1..10}; do echo "$second" >> out.txt sleep 1 done
If you run the parent script in the terminal, for example ...
~/parent.sh
... and after about 3 seconds, interrupt by pressing the key. When checking out.txt after a few seconds, it will look like ...
1 2 3
... thus indicating that the parent and child are finished with an interruption (by pressing a key). This is confirmed by checking ps -ef
in real time and observing that script processes are present before the interrupt and leave after the interrupt.
If the parent script is called cron, like ...
* * * * * ~/parent.sh
... the contents of out.txt are always ...
1 2 3 4 5 6 7 8 9 10
... thus indicating that at least the child has not completed the kill command. This is confirmed by checking ps -ef
in real time and observing that script processes are present before the interrupt, and only the interrupt is interrupted only by the parent process, but the child process is saved until it passes.
Attempts to solve ...
- Shell parameters can only be a factor here, since the non-interactive calls to the parent run
set -bm
(which entails PGIDs of children other than the parent’s PGIDs are in front). In addition, both scenarios show only hB options enabled, whether it is interactively executed or not. - I looked through the bash man for clues, but found nothing.
- I tried several web searches that included a lot of stackoverflow, but while some of them looked like this question, none of us are the same. The nearest answers entailed ...
- using wait to get the identifier of the child process and call kill on it - result: /parent.sh: line 30: kill: (17955) - operation not allowed "
- calling kill in a process group - leads to "~ / parent.sh: line 31: kill: (-15227) - the operation is not allowed" (kill using a child’s PGID that differs from the parent in a non-interactive way, due to the ability to control the task )
- iterate over current tasks and kill each
The problem with these solutions is that the parent runs as a regular user, while the child works as root via sudo (in the end it will be binary, not suid script), so the parent can not kill him? If this means that “Operation is not allowed” means why the process called by sudo can be killed when sending a keypress interrupt through the terminal?
The natural course is to avoid extra code unless it is necessary, i.e. since scripts behave correctly when interactively launched, if possible, it is much more preferable to simply use the same behavior when working non-interactively / using cron.
The bottom question is about what can be done to make the interrupt signal (or term) issued during operation without interactive interaction lead to the same behavior as the interrupt signal when starting in interactive mode?
Thanks. Any help is appreciated.