rsync 抑制 SIGINT 以捕获外部陷阱
rsync suppress SIGINT for trap outside
我正在尝试构建一个通用的 retry
shell 函数,以在上次失败时重新 运行 指定的 shell 命令几次,这是我的代码:
retry() {
declare -i number=
declare -i interrupt=0
trap "echo Exited!; interrupt=1;" SIGINT SIGTERM SIGQUIT SIGKILL
shift
for i in `seq $number`; do
echo "\n-- Retry ${i}th time(s) --\n"
$@
if [[ $? -eq 0 || $interrupt -ne 0 ]]; then
break;
fi
done
}
它非常适合wget
、curl
和其他各种常用命令。但是,如果我 运行
retry 10 rsync local remote
,传输过程中发送ctrl+c打断,报
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(700) [sender=3.1.3]
似乎rsync
抑制了内部的SIGINT和其他一些相关信号,然后return向外部调用者发送了一个代码20
。这个 return 代码没有使循环中断,然后我发送几个 ctrl+c 来中断下一个 rsync
命令。它仅在最后一次 ctrl+c 时打印 Exited!
并且 trap
捕获它。
问题:
为什么第一个return代码20没有使循环中断?
如何让trap
捕捉到SIGINT信号但是rsync
,如果没有,我该怎么办?
Why does it first return code 20 didn't make the loop break?
你是对的,rsync
确实捕获了某些信号并以 RERR_SIGNAL
(20) 退出。
How to let the trap catch the SIGINT signal but rsync, if not, what should I do?
因为 rsync
有它自己的处理程序,你不能做任何事情(可以使用一些 hack 来覆盖 rsync
中的信号处理程序,例如 LD_PRELOAD
。但它可能是不必要的复杂)。由于您的陷阱在当前 shell 中,您不知道 "command" 是否发出信号或以非零退出。
我假设你希望你的 retry
是通用的并且你不希望对 rsync
进行特殊处理(例如,不同的命令可能会以 75 信号退出而你不'想处理特殊情况)。
问题是您的陷阱处理程序未激活,因为当前进程 运行ning 进程 (rsync
) 接收到信号。您可以在后台 运行 您的命令并等待它完成。这将允许您从 retry
捕获信号。收到信号后,它会简单地杀死子进程。
#!/bin/bash
retry()
{
declare -i number=
declare -i i
declare -i pid
declare -i interrupted=0
trap "echo Exiting...; interrupted=1" SIGINT SIGTERM SIGQUIT
shift
# Turn off "monitor mode" so the shell doesn't report terminating background jobs.
set +m
for ((i = 0; i < number; ++i)); do
echo "\n-- Retry ${i}th time(s) --\n"
$@ &
pid=$!
# If command succeeded, break
wait $pid && break
# If we receive one of the signals, break
[[ $interrupted == 1 ]] && kill $pid && break
done
# Switch back to default behaviour
set -m
trap - SIGINT SIGTERM SIGQUIT
}
注意SIGKILL
是抓不到的。所以给它设下陷阱也没有意义。所以我已经删除了它。
我正在尝试构建一个通用的 retry
shell 函数,以在上次失败时重新 运行 指定的 shell 命令几次,这是我的代码:
retry() {
declare -i number=
declare -i interrupt=0
trap "echo Exited!; interrupt=1;" SIGINT SIGTERM SIGQUIT SIGKILL
shift
for i in `seq $number`; do
echo "\n-- Retry ${i}th time(s) --\n"
$@
if [[ $? -eq 0 || $interrupt -ne 0 ]]; then
break;
fi
done
}
它非常适合wget
、curl
和其他各种常用命令。但是,如果我 运行
retry 10 rsync local remote
,传输过程中发送ctrl+c打断,报
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(700) [sender=3.1.3]
似乎rsync
抑制了内部的SIGINT和其他一些相关信号,然后return向外部调用者发送了一个代码20
。这个 return 代码没有使循环中断,然后我发送几个 ctrl+c 来中断下一个 rsync
命令。它仅在最后一次 ctrl+c 时打印 Exited!
并且 trap
捕获它。
问题:
为什么第一个return代码20没有使循环中断?
如何让
trap
捕捉到SIGINT信号但是rsync
,如果没有,我该怎么办?
Why does it first return code 20 didn't make the loop break?
你是对的,rsync
确实捕获了某些信号并以 RERR_SIGNAL
(20) 退出。
How to let the trap catch the SIGINT signal but rsync, if not, what should I do?
因为 rsync
有它自己的处理程序,你不能做任何事情(可以使用一些 hack 来覆盖 rsync
中的信号处理程序,例如 LD_PRELOAD
。但它可能是不必要的复杂)。由于您的陷阱在当前 shell 中,您不知道 "command" 是否发出信号或以非零退出。
我假设你希望你的 retry
是通用的并且你不希望对 rsync
进行特殊处理(例如,不同的命令可能会以 75 信号退出而你不'想处理特殊情况)。
问题是您的陷阱处理程序未激活,因为当前进程 运行ning 进程 (rsync
) 接收到信号。您可以在后台 运行 您的命令并等待它完成。这将允许您从 retry
捕获信号。收到信号后,它会简单地杀死子进程。
#!/bin/bash
retry()
{
declare -i number=
declare -i i
declare -i pid
declare -i interrupted=0
trap "echo Exiting...; interrupted=1" SIGINT SIGTERM SIGQUIT
shift
# Turn off "monitor mode" so the shell doesn't report terminating background jobs.
set +m
for ((i = 0; i < number; ++i)); do
echo "\n-- Retry ${i}th time(s) --\n"
$@ &
pid=$!
# If command succeeded, break
wait $pid && break
# If we receive one of the signals, break
[[ $interrupted == 1 ]] && kill $pid && break
done
# Switch back to default behaviour
set -m
trap - SIGINT SIGTERM SIGQUIT
}
注意SIGKILL
是抓不到的。所以给它设下陷阱也没有意义。所以我已经删除了它。