我想创建一个 shell 脚本来防止 python 脚本在 Raspberry Pi 中崩溃。这个 python 脚本在重新启动时自动启动,但是,有时它会在运行时崩溃。
目前我的 shell 脚本如下:
#!/bin/sh
COMMAND='python home/pi/projects/mypythonscript.py'
LOGFILE=restart.txt
writelog() {
now=`date`
echo "$now $*" >> $LOGFILE
}
writelog "Starting"
while true ; do
$COMMAND
writelog "Exited with status $?"
writelog "Restarting"
done
我想问我是否可以创建两个命令行,以确保可以防止两个独立的脚本使用这个shell脚本崩溃?或者我是否必须为第二个 python 脚本创建一个新的 shell 脚本文件?
我正在考虑这样修改:
#!/bin/sh
COMMAND1='python home/pi/projects/mypythonscript1.py'
COMMAND2='python home/pi/projects/mypythonscript2.py'
LOGFILE=restart.txt
writelog() {
now=`date`
echo "$now $*" >> $LOGFILE
}
writelog "Starting"
while true ; do
$COMMAND1
$COMMAND2
writelog "Exited with status $?"
writelog "Restarting"
done
这个修改会起作用吗?我很感激任何建议,因为我对 Linux(debian)平台还很陌生。
答案1
如果您使用 systemd,您可以为每个命令创建一个服务,然后让 systemd 在崩溃时重新启动它。
就像是:
[Unit]
Description='description of script'
[Service]
ExecStart=/path/too/script
Restart=always
[Install]
WantedBy=multi-user.target
然后可以将其放入/etc/systemd/system
,运行后就systemctl daemon-reload
可以启动服务了。它也会在重新启动后启动。
答案2
如果您想从一个控制脚本处理任意数量的异步进程,可以使用以下方法:
#!/bin/sh
COMMAND1=(python home/pi/projects/mypythonscript1.py)
COMMAND2=(python home/pi/projects/mypythonscript2.py)
︙
rm -f COMMAND1_failed; ("${COMMAND1[@]}"; touch COMMAND1_failed)&
rm -f COMMAND2_failed; ("${COMMAND2[@]}"; touch COMMAND2_failed)&
︙
while true
do
if [ -e COMMAND1_failed ]
then
# Restart Command1
rm -f COMMAND1_failed; ("${COMMAND1[@]}"; touch COMMAND1_failed)&
fi
if [ -e COMMAND2_failed ]
then
# Restart Command2
rm -f COMMAND2_failed; ("${COMMAND2[@]}"; touch COMMAND2_failed)&
fi
︙
sleep 60
done
COMMAND1=(python home/pi/projects/mypythonscript1.py)
定义COMMAND1
为一个数组。这允许命令包含包含空格的单词;例如,类似的东西COMMAND1=(python "home/pi/projects/my python script1.py")
。"${COMMAND1[@]}"
类似于您使用$COMMAND1
;它运行您的第一个命令,并引用其组成词。(commandA; commandB)
本质上创建一个临时的两行脚本:命令A 命令B
所以("${COMMAND1[@]}"; touch COMMAND1_failed)
说“运行命令 #1,等待它完成,然后触摸(创建)一个名为COMMAND1_failed
.整个迷你脚本在后台运行,因此主脚本可以继续运行命令 #2,等等。- 实际上,您可能应该使用
failed
文件的完整路径名,并且可能将它们的名称放入变量中。 - 启动所有后台作业后,主脚本进入无限(永远)循环。如果该
COMMAND1_failed
文件存在,则意味着命令 #1 需要重新启动。 ETC。 sleep
根据需要调整。值太低,控制脚本可能会频繁运行,从而影响系统的性能。值太高,异步任务将无法及时重新启动,因此系统的响应能力会受到影响。
上面启动了所有进程,然后进入无限循环。这是一个简单的优化:
#!/bin/sh
︙
touch COMMAND1_failed
︙
while true
do
if [ -e COMMAND1_failed ]
then
# (Re)start Command1
rm -f COMMAND1_failed; ("${COMMAND1[@]}"; touch COMMAND1_failed)&
fi
︙
sleep 60
done
在创建所有必要的文件以使其看起来需要(重新)启动进程之后,它会在循环的第一次迭代时启动后台进程。唯一的区别是它列出了启动进程一次而不是两次的命令。COMMANDn_failed
也可以看看: