延迟终止脚本

Kus*_*nda 5 signals openbsd shell-script trap

我有一个这样的脚本(/bin/sh在 OpenBSD 上编写),它首先使用 更新一些 CVS 存储库的本地副本rsync,然后在我的机器上更新这些的检出版本。该脚本通过 OpenBSD 以 root 身份运行doas(OpenBSD 上的sudo“等效项”):

#!/bin/sh

int_handler () {
    echo 'Wait...' >&2
    quit=1
}

quit=0
trap int_handler INT

for r in CVSROOT src xenocara ports; do
    su cvsuser -c 'rsync --archive --itemize-changes --delete --omit-dir-times \
        "rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
        "/extra/cvs/$r/"'
done

trap - INT

[ "$quit" -eq 1 ] && exit

# rest of script updates checked-out CVS repositories from local copy
Run Code Online (Sandbox Code Playgroud)

这个想法是我可以Ctrl+Crsync循环运行时按下,以便稍后跳过脚本的第二部分(我可能并不总是想要运行,这取决于存储库中已更新的内容)而不会中断循环及其su+rsync进程。

这不起作用,rsync进程接收信号并终止(for循环的下一次迭代继续)。 rsync说(Ctrl+C多次按下直到脚本终止时):

^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(504) [receiver=3.1.3]
Wait...
rsync: [receiver] write error: Broken pipe (32)
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(1633) [sender=3.1.3]
^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(504) [receiver=3.1.3
]

rsync: [receiver] write error: Broken pipe (32)
Wait...
^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]
rsync error: received SIGUSR1 (code 19) at main.c(1440) [receiver=3.1.3]
Wait...
Run Code Online (Sandbox Code Playgroud)

根据对“ How to make ctrl+c /not/ interrupt the while-loop? ”问题的回答,至少在运行时bash,应该能够忽略INT信号,这将使子进程也忽略该信号。这并不理想,但我很乐意尝试。

因此,鉴于此,第二次尝试:

#!/usr/local/bin/bash

trap '' INT

for r in CVSROOT src xenocara ports; do
    su cvsuser -c 'rsync --archive --itemize-changes --delete --omit-dir-times \
        "rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
        "/extra/cvs/$r/"'
done

trap - INT

read -p 'Press enter or interrupt...' junk

# rest of script updates checked-out CVS repositories from local copy
Run Code Online (Sandbox Code Playgroud)

这同样允许rsync过程被中断Ctrl+C

好的,所以也许su是重置信号掩码的原因?第三次尝试:

#!/usr/local/bin/bash

trap '' INT

for r in CVSROOT src xenocara ports; do
    su -s /usr/local/bin/bash cvsuser -c \
        'trap "" INT; rsync --archive --itemize-changes --delete --omit-dir-times \
        "rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
        "/extra/cvs/$r/"'
done

trap - INT

read -p 'Press enter or interrupt...' junk

# rest of script updates checked-out CVS repositories from local copy
Run Code Online (Sandbox Code Playgroud)

不,没有快乐。该rsync过程仍然可以以相同的方式中断。

有没有办法让脚本按照我(最初)预期的方式工作?

bash在我的机器上是 4.4.23 版。这/bin/shpdksh在 POSIX 模式下运行的 OpenBSD 上的本机变体。

ilk*_*chu 5

那么,既然您并不真正想要中断,那么如何在终端级别禁用它呢stty intr ""?这将使^C出现在输入缓冲区中作为任何普通字符,我们可以从那里读取它。

这对我在 Linux 上有效:

#!/bin/bash

t=$(stty -g)
stty intr ""
echo please hold
sleep 5
stty "$t"

# short timeout, just check if there was any input earlier
read -n1 -t0.1 a
[[ "$a" = $'\003' ]] && echo "you hit ^C"
Run Code Online (Sandbox Code Playgroud)

(我无法在 OpenBSD 上进行测试,但我认为终端设置内容是标准的。)