【问题标题】:Process control in bash scriptsbash 脚本中的进程控制
【发布时间】:2013-12-03 21:46:16
【问题描述】:

我对 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 中遗漏了一些东西。也许有更好的方法来代替我的想法。

谢谢大家!

【问题讨论】:

  • 当你尝试它时会发生什么?此外,如果 function2 运行速度很快,您最多可以在 10:00 运行 6 次,并且您在迭代之间等待 10 秒,因为您将在 10:00:00、10:00:10、10:00:20 运行

标签: bash loops process


【解决方案1】:

我认为这可行。一些注意事项:

  1. 即使你停止一个进程,它的子进程也会继续愉快地运行。如果您也想停止这些,则需要在父级中捕获 STOP 和 CONT 信号以停止和恢复子级。

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

  3. 您可以将kill -SIGSTOP 缩短为kill -STOP,与CONT 相同

这是一个示例演示代码:

#!/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

【讨论】:

    【解决方案2】:

    与其运行一个不断检查是否为 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 派生出一个自己的孩子,您必须确保它的编写方式能够在它自己停止时阻止它们。

    【讨论】:

      【解决方案3】:

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

      可以这么简单:

      #!/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.
      

      【讨论】:

        【解决方案4】:

        感谢大家的即时答复,对于延误,我深表歉意。我遇到了系统磁盘驱动器故障(!!)

        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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-17
          • 1970-01-01
          • 2012-08-12
          • 2010-10-06
          • 1970-01-01
          • 2013-07-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多