在shell脚本中实现无限等待

在shell脚本中实现无限等待,shell,unix,Shell,Unix,这听起来可能很琐碎,但我很确定这个问题没有被问到,或者至少我找不到 我正在寻找一种方法,用shell脚本构建一个无限等待(不一定是一个循环),这样它就永远等待,并且可以被杀死(或者从技术上讲,接收一个SIGTERM)。以下是已知的可能构造和反对它们的参数: 为true时;做睡眠1;已完成这几乎可以完成,但由于睡眠是一个外部命令,因此当我向正在运行的脚本发送SIGTERM时,它必须先等待睡眠完成,然后再处理信号。将sleep 1更改为类似sleep 10的内容,滞后将变得明显。此外,该解决方案每1

这听起来可能很琐碎,但我很确定这个问题没有被问到,或者至少我找不到

我正在寻找一种方法,用shell脚本构建一个无限等待(不一定是一个循环),这样它就永远等待,并且可以被杀死(或者从技术上讲,接收一个
SIGTERM
)。以下是已知的可能构造和反对它们的参数:

  • 为true时;做睡眠1;已完成
    这几乎可以完成,但由于
    睡眠
    是一个外部命令,因此当我向正在运行的脚本发送
    SIGTERM
    时,它必须先等待
    睡眠
    完成,然后再处理信号。将
    sleep 1
    更改为类似
    sleep 10
    的内容,滞后将变得明显。此外,该解决方案每1秒唤醒一次CPU,这并不理想
  • 为true时;一定要读书;完成
    stdin
    为tty时,这是完美的
    read
    是一个shell内置项,
    SIGTERM
    立即到达脚本。但是,当
    stdin
    /dev/null
    时,脚本会通过在
    /dev/null
    上永远运行
    read
    来消耗所有CPU
  • 因此,需要一个永远等待的shell内置构造。浏览一下
    mandash
    我没有找到这样一个-唯一的阻塞内置是
    read
    wait
    ,我不知道如何使用
    wait
    构建一个理想的

    答案应该适用于POSIX shell(实际上是
    dash
    ),或者不如Bash

    附加说明。

    第一个例子不能完美工作的情况比我想象的要复杂。使用以下shell脚本:

    #!/bin/sh
    echo $$
    while true; do
        sleep 100
    done
    
    如果你在另一个tty杀死它,它会立即终止。当你尝试做诱捕时,有趣的事情就开始了。使用此脚本:

    #!/bin/sh
    at_term() {
        echo 'Terminated.'
        exit 0
    }
    trap at_term TERM
    echo $$
    while true; do
        sleep 20
    done
    

    发生的情况在示例1中有确切描述。这在bash、dash和zsh中发生。在这种情况下,我正在寻找一个“完美的”无限外观构造。

    发送到进程的SIGTERM由内核传递到进程,无论进程是否处于睡眠状态

    尝试尝试一下,也许像这样(bash示例)


    您的第二个选项有什么问题,但强制它从
    stdin
    读取?(需要
    bash


    您可以使用命名管道进行读取:

    mkfifo /tmp/mypipe
    #or mknode /tmp/mypipe p
    
    如果以后要向管道发送不同的任意“信号”,可以将读取与case语句结合使用,以采取适当的操作(甚至是有用的操作)

    读取信号时;做
    大写“$SIGNAL”
    *退出*)中断;;
    *)echo“信号$signal不受支持”>/dev/stderr;;
    以撒
    完成
    如果您有接受浮点秒的GNU coreutils,您可以尝试:

    sleep inf
    

    这将一直阻止,直到64位时间戳环绕。

    这里有一个没有循环的解决方案:

    #!/usr/local/bin/dash
    
    echo $$
    
    # -$$: kill process group (parent and children)
    #trap 'trap - TERM; kill 0' TERM
    #trap 'trap - INT TERM; kill 0' INT TERM
    
    trap 'trap - TERM; kill -s TERM -- -$$' TERM
    
    tail -f /dev/null & wait
    
    exit 0
    

    为什么不使用“永远睡眠”?这是为了永久阻止。

    当我发送一个
    SIGTERM
    到一个
    dash
    循环执行
    sleep 100
    时,它会立即退出。你需要这个做什么?如果进程应该持续,但什么也不做,它可能会给自己发送一个
    SIGSTOP
    ,因此,有理由怀疑它可能并不总是可用的。如果有人能提供一些关于/dev/stdin:)的文档,那就太好了。当stdin被重定向到/dev/null时,它会崩溃。把它放在a.sh中,运行
    bash a.sh
    ,然后看到CPU被吃掉了……是的,这个几乎是完美的。我会看看是否有人能想出更简单的方法,或者我会接受……接受你的答案:)这在任何情况下都是通用的。谢谢你的解决方案!就我个人而言,我认为它比使用
    阅读
    更优雅,而且它工作得非常完美!你的剧本很神奇!这是唯一一个做我想做的(对信号15的响应)。你能详细解释一下吗?那你为什么一个接一个地重复这个陷阱呢?在trap中编写的所有内容对我来说都不清楚,为什么&tail之后,为什么还要等待?@MohammedNoureldin
    trap-TERM
    部分删除了脚本中现有的trap处理程序,这样就不会再次捕获相同的信号。
    kill-s TERM--$$
    部分将
    SIGTERM
    发送到同一进程组中的所有进程。有效地执行所有子进程和子进程(包括脚本本身)。也就是说,就
    kill
    而言,负PID是PGID,但我们需要额外的
    --
    以避免与命令开关混淆。由于
    SIGTERM
    处理程序已被删除,当接收到第二个
    SIGTERM
    信号(它在旧处理程序中发送)时,脚本将终止。如果您没有
    inf
    (例如在alpine/sh上),您可以始终将其放入无限循环中。无论哪种方式,这都是有效的。如果只有shell脚本(而不是sleep(1)进程)接收到信号,这就不起作用。
    mkfifo /tmp/mypipe
    #or mknode /tmp/mypipe p
    
    while read SIGNAL; do
        case "$SIGNAL" in
            *EXIT*)break;;
            *)echo "signal  $SIGNAL  is unsupported" >/dev/stderr;;
        esac
    done < /tmp/mypipe
    
    #!/bin/sh
    at_term() {
      echo 'Terminated.'
      exit 0
    }
    trap at_term TERM
    echo $$
    while true; do
      sleep 20 &
      wait $!
    done
    
    sleep inf
    
    #!/usr/local/bin/dash
    
    echo $$
    
    # -$$: kill process group (parent and children)
    #trap 'trap - TERM; kill 0' TERM
    #trap 'trap - INT TERM; kill 0' INT TERM
    
    trap 'trap - TERM; kill -s TERM -- -$$' TERM
    
    tail -f /dev/null & wait
    
    exit 0