How do I terminate everything at a certain subshell level in Bash, without using “kill 0”?

StackOverflow https://stackoverflow.com/questions/11942380

  •  26-06-2021
  •  | 
  •  

문제

Context:

Say I have:

(
#outer subshell
    {
    #inner command group, pipe-connected to ensure simultaneous invocation
        do_first_thing
        #die, somehow
    } | { 
    #inner command group, pipe-connected to ensure simultaneous invocation
        sleep 10
        do_second_thing
    }
)
echo "out"

I have an outer subshell (doesn't have to be one; it can be a command group, or could be removed entirely). Inside that, I have two pipe-connected command groups that get invoked simultaneously. I want both groups to start executing, and then, when the first group finishes (the second will still be sleeping), I want execution of the outer subshell to stop, where the #die, somehow line is.

Question:

What should I do to ensure that when the #die, somehow line is reached, everything in the #outer subshell level terminates, but execution continues after it (i.e. out gets printed)?

What I've Tried:

One solution is to use kill 0 (kill everything in the current process group) to get out of both internal command groups, but then the echo "out" will never happen; the whole group will be killed, not just the outer subshell.

I've also tried temporarily overriding and then unseting the exit function, but that just seems to push the problem to a different location. Perhaps I'm doing it wrong; I'm by no means a Bash guru.

Why?

Without getting into too much detail, the weird subshell-connected command groups are necessary because using & to fork out processes does not work deterministically on my system (embedded *nix). As a result, the pipe-connected groups ensure that if do_first_thing runs for too long (10 seconds, in the above example), do_second_thing will occur. The actual use case is significantly more complex, but this is the root of the problem.

Cheers!

도움이 되었습니까?

해결책

#!/bin/bash                                                                     
(
  #outer subshell                                                                 
  {
    #inner command group, pipe-connected to ensure simultaneous invocation      
    first_step;
    ps -ef | grep './lol.bash' | awk '{print $2}' | xargs kill;
    #die, somehow                                                           
  } | {
    #inner command group, pipe-connected to ensure simultaneous invocation      
    ./lol.bash;
  }
)
echo "out"

and lol.bash contains your sleep and then the so called "second_step"... it's not very clean, but it turns.

an other way is to make a loop in the second part, that check if step one is done, for an amount of time, and then leave if so, or clean all things in first step and does some stuff if time is up...

nb: obviously you can launch at every step a distinct process, and then kill it when you want... (you just need to khnow the pid...)

다른 팁

Would a structure along these lines be suitable?

touch /tmp/sentinel-file
(do_first_thing; rm /tmp/sentinel-file) &
pid=$!
sleep 10
if [[ -r /tmp/sentinel-file ]]
then
  kill $pid
  rm /tmp/sentinel-file
  do_second_thing
fi

There are some race conditions there if you run multiple copies of this, but in some ways it might be a bit cleaner than what you're doing now.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top