我有一台中央服务器,在该服务器中,我定期从cron启动脚本来检查远程服务器.该检查是按顺序执行的,因此首先是一台服务器,然后是另一台服务器.
该脚本(从中央服务器)在远程计算机上启动另一个脚本(将其称为update.sh),并且该脚本(在远程计算机上)正在执行以下操作:
processID=`pgrep "processName"`
kill $processID
startProcess.sh
该进程被杀死,然后在脚本startProcess.sh中启动,如下所示:
pidof "processName"
if [ ! $? -eq 0 ]; then
nohup "processName" "processArgs" >> "processLog" &
pidof "processName"
if [! $? -eq 0]; then
echo "Error: failed to start process"
...
update.sh,startprocess.sh及其启动的实际二进制文件位于从中央服务器装入的NFS上.
现在有时发生的是,我尝试在startprocess.sh中启动的进程未启动,并且出现了错误.奇怪的是,它是随机的,有时一台计算机上的进程启动,而同一台计算机上的另一时间没有启动.我正在检查大约300台服务器,并且错误始终是随机的.
还有另一件事,远程服务器位于3个不同的地理位置(美国2个,欧洲1个),中央服务器在欧洲.我到目前为止发现的是,美国的服务器比欧洲的服务器有更多的错误.
首先,我认为该错误与kill有一定关系,因此我在kill和startprocess.sh之间添加了sleep,但这没有任何区别.
同样,似乎startprocess.sh的进程根本没有启动,或者启动时发生了某些事情,因为日志文件中没有输出,并且日志文件中应该有输出.
所以,我在这里寻求帮助
是否有人遇到过此类问题,或者知道可能出什么问题了?
谢谢你的帮助
解决方法:
(对不起,但我最初的回答是错误的……这是更正)
使用$?在startProcess.sh中获取后台进程的退出状态会导致错误的结果.男人bash指出:
Special Parameters
? Expands to the status of the most recently executed foreground
pipeline.
正如您在评论中提到的那样,获取后台进程退出状态的正确方法是使用内置的等待.但是,为此bash必须处理SIGCHLD信号.
我为此做了一个小型测试环境,以展示其工作方式:
这是一个脚本loop.sh,可以作为后台进程运行:
#!/bin/bash
[ "$1" == -x ] && exit 1;
cnt=${1:-500}
while ((++c<=cnt)); do echo "SLEEPING [$$]: $c/$cnt"; sleep 5; done
如果arg为-x,则退出且退出状态为1,以模拟错误.如果arg为num,则等待num * 5秒以打印SLEEPING [< PID>]< counter //< max_counter>.到标准输出.
第二个是启动器脚本.它在后台启动3个loop.sh脚本并显示其退出状态:
#!/bin/bash
handle_chld() {
local tmp=()
for i in ${!pids[@]}; do
if [ ! -d /proc/${pids[i]} ]; then
wait ${pids[i]}
echo "Stopped ${pids[i]}; exit code: $?"
unset pids[i]
fi
done
}
set -o monitor
trap "handle_chld" CHLD
# Start background processes
./loop.sh 3 &
pids+=($!)
./loop.sh 2 &
pids+=($!)
./loop.sh -x &
pids+=($!)
# Wait until all background processes are stopped
while [ ${#pids[@]} -gt 0 ]; do echo "WAITING FOR: ${pids[@]}"; sleep 2; done
echo STOPPED
handle_chld函数将处理SIGCHLD信号.通过设置选项监视器,可以使非交互式脚本接收SIGCHLD.然后将陷阱设置为SIGCHLD信号.
然后启动后台进程.它们的所有PID都被记住在pids数组中.如果收到SIGCHLD,则在/ proc /目录中检查停止了哪个子进程(缺少的子进程)(也可以使用内置的kill -0< PID> bash进行检查).等待之后,后台进程的退出状态存储在著名的$?中.伪变量.
主脚本等待所有pid停止(否则它无法获取其子级的退出状态),并且它自身停止.
输出示例:
WAITING FOR: 13102 13103 13104
SLEEPING [13103]: 1/2
SLEEPING [13102]: 1/3
Stopped 13104; exit code: 1
WAITING FOR: 13102 13103
WAITING FOR: 13102 13103
SLEEPING [13103]: 2/2
SLEEPING [13102]: 2/3
WAITING FOR: 13102 13103
WAITING FOR: 13102 13103
SLEEPING [13102]: 3/3
Stopped 13103; exit code: 0
WAITING FOR: 13102
WAITING FOR: 13102
WAITING FOR: 13102
Stopped 13102; exit code: 0
STOPPED
可以看出,退出代码已正确报告.
我希望这可以有所帮助!
标签:bash,linux,bash,bash,bash
来源: https://codeday.me/bug/20191029/1956947.html