Answers:
我为我编写的打印后台处理程序执行此操作,这只是一个shell脚本:
#!/bin/sh
if ps -ef | grep -v grep | grep doctype.php ; then
exit 0
else
/home/user/bin/doctype.php >> /home/user/bin/spooler.log &
#mailing program
/home/user/bin/simplemail.php "Print spooler was not running... Restarted."
exit 0
fi
它每两分钟运行一次,非常有效。如果由于某种原因该进程未运行,我会通过电子邮件将特殊信息发送给我。
grep -v grep | grep doctype.php
你可以做grep [d]octype.php
。
&
如果是cron运行脚本,则不需要。
使用flock
。是新的 好多了
现在,您不必自己编写代码。在此处查看更多原因:https : //serverfault.com/a/82863
/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
正如其他人所说,编写和检查PID文件是一个很好的解决方案。这是我的bash实现:
#!/bin/bash
mkdir -p "$HOME/tmp"
PIDFILE="$HOME/tmp/myprogram.pid"
if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= |
grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then
echo "Already running."
exit 99
fi
/path/to/myprogram > $HOME/tmp/myprogram.log &
echo $! > "${PIDFILE}"
chmod 644 "${PIDFILE}"
>
”与“ >>
”。对于那个很抱歉。
[ -e "${PIDFILE}" ]
”。如果不存在,则它将在后台启动程序,将其PID写入文件(“ echo $! > "${PIDFILE}"
”),然后如果确实存在PID文件,则该脚本将检查您自己的进程(“ ps -u $(whoami) -opid=
”),并查看您是否正在使用相同的PID(“ grep -P "^\s*$(cat ${PIDFILE})$"
”)运行该进程。如果不存在,则它将启动该进程。像以前一样编程,用新的PID覆盖PID文件,然后退出,我认为没有理由修改脚本;对吗
不要尝试通过cron做到这一点。让cron无论如何都运行脚本,然后让脚本确定程序是否正在运行,并在必要时启动它(请注意,您可以使用Ruby或Python或您喜欢的脚本语言来执行此操作)
您也可以直接在crontab中将其作为单行代码执行:
* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
ps -ef|grep [c]ommand
-eq 0] && <command>,其中将命令的首字母括在方括号中会将其从grep结果中排除。
[ "$(ps -ef|grep [c]ommand|wc -l)" -eq 0 ] && <command>
[ $(grep something | wc -l) -eq 0 ]
是一种真正的回旋方式! grep -q something
。所以,您只需要ps -ef | grep '[c]ommand' || command
grep -c
。)
当我运行php脚本时,我这样做的方式是:
* * * * * php /path/to/php/script.php &
<?php
if (shell_exec('ps aux | grep ' . __FILE__ . ' | wc -l') > 1) {
exit('already running...');
}
// do stuff
该命令正在系统进程列表中搜索当前php文件名(如果存在),则行数计数器(wc -l)会大于1,因为搜索命令本身包含文件名
因此,如果您运行php crons,则将以上代码添加到php代码的开头,它将仅运行一次。
作为Earlz答案的后续措施,您需要一个包装器脚本,该脚本在启动时创建$ PID.running文件,并在结束时删除。包装脚本会调用您希望运行的脚本。如果目标脚本失败或出错,则必须使用包装器,以删除pid文件。
这样,lockrun
您就无需为cron作业编写包装器脚本。 http://www.unixwiz.net/tools/lockrun.html
# one instance only (works unless your cmd has 'grep' in it)
ALREADY_RUNNING_EXIT_STATUS=0
bn=`basename $0`
proc=`ps -ef | grep -v grep | grep "$bn" | grep -v " $$ "`
[ $? -eq 0 ] && {
pid=`echo $proc | awk '{print $2}'`
echo "$bn already running with pid $pid"
exit $ALREADY_RUNNING_EXIT_STATUS
}
更新..使用羊群的更好方法:
/usr/bin/flock -n /tmp/your-app.lock /path/your-app args
我建议以下内容作为对rsanden答案的改进(我会发表评论,但没有足够的声誉...):
#!/usr/bin/env bash
PIDFILE="$HOME/tmp/myprogram.pid"
if [ -e "${PIDFILE}" ] && (ps -p $(cat ${PIDFILE}) > /dev/null); then
echo "Already running."
exit 99
fi
/path/to/myprogram
这避免了可能的错误匹配(以及grepping的开销),并且抑制了输出并且仅依赖于ps的退出状态。
ps
命令将匹配系统上其他用户的PID,而不仅仅是您自己的PID。-u
在ps
命令中添加“ ”会更改退出状态的工作方式。
简单的自定义php就足以实现。无需与shell脚本混淆。
假设您要运行php /home/mypath/example.php(如果未运行)
然后使用以下自定义php脚本执行相同的工作。
创建以下/home/mypath/forever.php
<?php
$cmd = $argv[1];
$grep = "ps -ef | grep '".$cmd."'";
exec($grep,$out);
if(count($out)<5){
$cmd .= ' > /dev/null 2>/dev/null &';
exec($cmd,$out);
print_r($out);
}
?>
然后在您的cron中添加以下内容
* * * * * php /home/mypath/forever.php 'php /home/mypath/example.php'
文件:https://www.timkay.com/solo/
solo是一个非常简单的脚本(10行),可防止程序一次运行多个副本。使用cron来确保作业在上一个作业完成之前不会运行是很有用的。
例
* * * * * solo -port=3801 ./job.pl blah blah