我有一个脚本启动程序(bash)在后台执行Python脚本,所以我可以启动它然后关闭terminal / ssh连接,让脚本工作。
它接受要运行的脚本的名称以及传递的可选参数。然后它启动Python脚本(分离)并在同一目录中创建一个带有PID(Python脚本)的文件,这样我以后可以重新连接到服务器并使用此文件中的PID终止此后台进程。
此PID文件用于防止相同的脚本已经运行(单例)。
问题是我无法弄清楚在Python脚本完成其工作后如何删除此PID文件。我需要在bash脚本中实现它,没有Python解决方案(因为我想在所有情况下使用它)或屏幕工具。这个主管(在脚本完成工作后将删除PID文件)也应该在后台运行(!),所以我可以做同样的事情:关闭终端会话。
到目前为止我尝试过:
#!/bin/bash
PIDFILE=$1.pid
if [ -f $PIDFILE ]; then
echo "Process is already running, PID: $(< $PIDFILE)"
exit 1
else
nohup python $1 "${@:2}" > /dev/null 2>&1 &
PID=$!
echo $PID > $PIDFILE
# supervisor
nohup sh -c "wait $PID; rm -f $PIDFILE" > /dev/null 2>&1 &
fi
在此示例中,PID文件立即被删除,因为 wait 命令立即返回(我认为这是因为新进程不是当前进程的子进程,所以等待在这种情况下不起作用,如我所料。)
您对如何实施有任何想法吗? 基本上,我需要一些东西来替换这一行
nohup sh -c "wait $PID; rm -f $PIDFILE" > /dev/null 2>&1 &
将等到上一个脚本(在本例中为Python)完成其工作,然后删除PID文件。
UPD:好的,问题在于等待命令,因为它无法等待非子进程。工作解决方案是用 while 循环替换它:
#!/bin/bash
function cleanup {
while [ -e /proc/$1 ]; do
sleep 1;
done
rm -f $PIDFILE
}
PIDFILE=$1.pid
if [ -f $PIDFILE ]; then
echo "Process is already running, PID: $(< $PIDFILE)"
exit 1
else
python $1 "${@:2}" > /dev/null 2>&1 &
PID=$!
echo $PID > $PIDFILE
cleanup $PID > /dev/null 2>&1 &
disown
fi
答案 0 :(得分:1)
对于shell脚本,请使用traps:
#!/bin/bash
function finish {
wait $PID
rm $PIDFILE > /dev/null 2>&1 &
}
trap finish EXIT
trap "exit 2; finish" SIGINT
PIDFILE=$1.pid
if [ -f $PIDFILE ]; then
echo "Process is already running, PID: $(< $PIDFILE)"
exit 1
else
nohup python $1 "${@:2}" > /dev/null 2>&1 &
PID=$!
echo $PID > $PIDFILE
fi
Traps允许您捕获signals并对其进行响应,因此在上面的代码中, EXIT 信号(正常完成)将执行完成,删除$PIDFILE
。在 SIGINT (用户请求使用ctrl-c退出)时,脚本将删除$PIDFILE
并以2退出。
直接在python中:如果你想手动处理它,请看看atexit。我没有查看源代码,但看起来它实现traps以便注册清理函数:
import atexit
import os
def cleanup():
os.unlink(pidfile)
atexit.register(cleanup)
或者自动化pidfile处理checkout pid,它将自行处理阻止同时执行:
from pid import PidFile
with PidFile():
do_something()
或更好
from pid.decorator import pidfile
@pidfile()
def main():
pass
if __name__ == "__main__":
main()