SIGINT propagation for background process vs for subshell - bash

I have two programs in two files that I run with bash:
The first:
(sleep 100) &
wait
The second:
sleep 100 &
wait
If I send a SIGINT to the first program, it also kills my sleep command. But for the second the sleep command remains and isn't killed.
Why the difference?
Thanks so much!

Related

How can I send a signal without the shell waiting for the currently running program to finish?

If I send a signal using kill, it seems to wait until the current program (in this example sleep 1000) finishes running. When I instead send SIGINT via pressing Ctrl+C in the shell, it receives the interrupt immediately however.
What I want, however, is for the interrupt to be received immediately after sending the signal via kill. Also, why does it behave like I would want it to when I press Ctrl+C?
#!/usr/bin/env sh
int_after_a_while() {
local pid=$1
sleep 2
echo "Attempting to kill $pid with SIGINT"
# Here I want to kill the process immediately, but it waits until sleep finishes
kill -s INT $pid
}
trap "echo Interrupt received!" INT
int_after_a_while $$ &
sleep 1000
I would appreciate any help on this issue. Thanks in advance!
As noted in the referenced answer https://unix.stackexchange.com/questions/282525/why-did-my-trap-not-trigger/282631#282631 the shell will normally wait for a utility to complete before running a trap. Some alternatives are:
Start the long running process in the background, then wait for it using the wait builtin. When a trapped signal is received during such a wait, the wait is interrupted and the trap is taken. Unfortunately, the exit status of wait does not distinguish between the child process exiting on a signal and a trap occurring. For example
sleep 1000 &
p=$!
wait "$p"
Send a signal to the whole process group via kill -s INT 0. The effect is much like if the user had pressed Ctrl+C, but may be more extreme than you want if your script is run from another script.
Use a shell such as zsh or FreeBSD sh that supports set -o trapsasync which allows running traps while waiting for a foreground job.

Why does "(sleep 10 & sleep 1); wait" return after 1 second instead of 10?

wait without arguments is supposed to wait for all child processes, however
(sleep 10 & sleep 1); wait
returns after 1 second instead of 10, and so it's failing to wait for sleep 10 to finish.
Why is that, and how could I fix it?
The parentheses create a subshell—an entirely new shell process just for those two commands.
The wait command only waits for a shell’s own children (in fact, that’s all it can wait for); grandchildren don’t count. Since the sleep processes are children of the subshell instead of the main shell, they cannot be waited for.
Therefore, what happens is:
Subshell is created to run sleep 10 & sleep 1, and the main shell waits for it to finish
Subshell runs sleep 10, and continues processing immediately because of &
Subshell runs sleep 1, and waits for it to finish
One second later, sleep 1 exits.
The subshell is out of commands to process, so quits.
All of the subshells children (i.e., sleep 10) are orphaned, and re-parented to the init process (not the original shell).
The main shell continues to the wait command.
Because the shell has no children, wait returns immediately.
Nine seconds later, sleep 10 exits, and init cleans it up.
The only way to get wait to recognize a command is to not exit it in a subshell. In this example, you can achieve that by using curly braces, or by omitting the braces entirely. In either case, first sleep 10 will be run, then sleep 1 will be run, and when sleep 1 finishes wait will run until sleep 10 finishes.

Wait for one of two processes in shell script

I am running a couple of background processes in my shell script. I want to exit the script when one of the two processes exit.
If I apply:
wait $PID1
wait $PID2
It'll will wait for process 1 to complete and then wait for process 2. Same happens for:
command 1 && command 2 && wait
Is there any way I could perform an or operation on the wait command?
You can trap SIGCHLD:
trap 'exit 0' SIGCHLD

Stop a script after a given time in Unix bash

I have a bash script which is runnnig another script. What i want is something like this :
#in scriptA.sh
./scriptB
wait 10 seconds and kill scriptB
Is it doable ?
Thanks.
./scriptB &
sleep 10s
kill $!
How it works
./scriptB &
This starts scriptB in the background.
sleep 10s
This waits 10 seconds
kill $!
This kills the most recently executed background process.
kill will kill any process given is process ID. $! is the process ID of the most recently executed background process.

How do you stop two concurrent processes?

In my web development workflow, I have two processes:
watching my folder for changes
previewing my site in the browser
I want to be able to run them and then later stop them both at the same time. I've seen everyone suggesting using the ampersand operator:
process_1 & process_2
But pressing Ctrl + C only stops the second one. I have to kill the first one manually. What am I missing in this approach?
You can have the foreground script explicitly kill the subprocesses in response to SIGINT:
#!/bin/sh
trap 'kill $pid1 $pid2' 2
cmd1 &
pid1=$!
cmd2 &
pid2=$!
wait
There is a race condition in this example: if you send SIGINT to the parent before pid1 is assigned, kill will emit a warning message and neither child will be terminated. If you send SIGINT before pid2 is assigned, only the process running cmd1 will be sent the signal. In either case, the parent will continue running and a second SIGINT can be sent. Some versions of kill allow you to avoid this race condition by sending a signal to the process group using kill -$$, but not all versions of kill support that usage. (Note that if either child process does not terminate in response to the signal, the parent will not exit but continue waiting.)
How about writing two scripts, one containing
./process_1 &
./process_2 &
and a second containing
killall process_1
killall process_2
Start both prcesses by running the first script, and end them by running the second script.

Resources