bash脚本中的进程控制

时间:2013-12-03 21:46:16

标签: bash loops process

我对bash脚本中的进程控制感到有点困惑。

我想要的是运行特定的功能/例程,并在10:00停止它们然后运行其他一些功能。当“其他功能”结束时,我希望第一个功能完全从它们停止时的位置继续。

例如,假设我在09:50运行main.sh。我希望function_one在时间为10:00时停止,运行function_two然后继续使用function_one处于准确状态。毋庸置疑,function_one可能非常复杂,并且本身也有后台子进程。

$ cat main.sh
#!/bin/bash
source functions.sh
function_one &
echo $! > function_one_running_in_background_PID.txt

while true; do 
    sleep 10s
    if [[ $(date +%H%M) = 1000 ]]; then
        kill -SIGSTOP $(<function_one_running_in_background_PID.txt)
        echo Time is 10
        function_two
        kill -SIGCONT $(<function_one_running_in_background_PID.txt)
    fi
done


$ cat functions.sh
#!/bin/bash
function function_one { 
for i in {1..100000}; do echo 1st function: $i; sleep 1; done 
}
function function_two { 
for i in {1..100}; do echo 2nd function: $i; sleep 1; done 
}

如果上述情况可以,请告诉我吗? “也许”我在bash中遗漏了一些东西。也许有更好的方法来做到这一点,而不是我的想法。

谢谢大家!

4 个答案:

答案 0 :(得分:1)

我认为这可行。一些说明:

  1. 即使您停止某个流程,其子流程也会继续愉快地运行。如果你想要阻止那些,那么你需要在父母中捕获STOP和CONT信号以停止和恢复孩子。

  2. 而是将PID保存在文件中,为什么不保存在变量中?

  3. 您可以将kill -SIGSTOP缩短为kill -STOP,同样适用于CONT

  4. 以下是一个示例代码:

    #!/bin/sh -e
    
    f1() { for i in {1..1000}; do echo f1 $i; sleep 1; done; }
    f2() { for i in {1..1000}; do echo f2 $i; sleep 1; done; }
    
    f1 &
    PID1=$!
    f2 &
    PID2=$!
    kill -STOP $PID2
    
    turn=1
    while :; do
        if test $turn = 1; then
            kill -STOP $PID1
            kill -CONT $PID2
            turn=2
        elif test $turn = 2; then
            kill -STOP $PID2
            kill -CONT $PID1
            turn=1
        fi
        sleep 5
    done
    

答案 1 :(得分:1)

不是运行一个不断检查是否为10:00的繁忙循环,而是计算出直到10:00的多少秒,并在停止第一个过程之前停留很长时间。不需要临时文件,因为您可以将进程ID存储在另一个参数中,直到需要为止。

t=$(( $(date +%s --date 1000) - $(date +%s) ))
function_one & f1_pid=$!
sleep $t
kill -STOP $f1_pid
function_two
kill -CONT $f1_pid

如果function_one分拣自己的孩子,你必须确保它是以这样的方式写的,以便在它自己停止时停止它们。

答案 2 :(得分:1)

为了捕获所有的孩子,我想他们将属于同一个进程组,由启动它们的程序启动。杀死所有儿童,大孩子等等。

可能就是这么简单:

#!/bin/bash

#set the 'at' timer on 22:00 to give self a signal (see 'man at' )
at 22:00 <<<"/usr/bin/kill -SIGCONT $$" 

#gentlemen...start your engines..ehrm..programs!
"/path/firstset/member1.sh" &
"/path/firstset/member2.sh" &
"/path/firstset/member3.sh" &
"/path/firstset/member4.sh" &

while :
do
    kill -SIGSTOP "$$"               #<--now we halt this script.
                                     # wait for SIGCONT given by 'at' 
                                     # Very nicely scheduled on 22:00
    #when waking up:
    PLIST=$(pgrep -g "$$")           # list PIDs of group (= self + subtree)
    PLIST=${PLIST/"$$"/}             # but not self, please

    kill -SIGSTOP $PLIST             #OK it is 22:00, halt the old bunch 

    "/path/secondset/member1.sh" &   # start the new bunch
    "/path/secondset/member2.sh" &
    "/path/secondset/member3.sh" &
    "/path/secondset/member4.sh" &

    wait                             # wait till they are finished

    kill -SIGCONT $PLIST             #old bunch can continue now, 
done                                 #until next scheduled event.

答案 3 :(得分:0)

谢谢大家的即时答复,我为延误道歉。我的系统磁盘驱动器出现故障(!!)

Janos,如果f1中有后台进程,会发生什么?我怎么能阻止所有这些?

#!/bin/sh -e

f1() { 
f3 &
f4 &
}

f2() { for i in {1..1000}; do echo f2 $i; sleep 1; done; }
f3() { for i in {1..1000}; do echo f3 $i; sleep 1; done; }
f4() { for i in {1..1000}; do echo f4 $i; sleep 1; done; }


f1 &
PID1=$!
f2 &
PID2=$!
kill -STOP $PID2

while :; do
    if [[ $(date +%S) = *0 ]]; then
        kill -STOP $PID1
        kill -CONT $PID2
    elif [[ $(date +%S) = *5 ]]; then
        kill -STOP $PID2
        kill -CONT $PID1
    fi
    sleep 1
done