Answers:
有一些程序可以自动执行此功能,自己消除烦恼和潜在的错误,还可以通过在后台使用植绒来避免过时的锁定问题(如果您只是使用触摸,则存在风险) 。我用lockrun
和lckdo
过去一样,但现在有flock
(1)(在UTIL-linux下的新望版本),这是伟大的。真的很容易使用:
* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job
flock -n file command
和flock -n file -c command
?
-c
通过外壳程序运行了指定的命令(按照联机帮助页),而“裸”(非-c
)形式只是exec
给定的命令。在shell中放一些东西可以使您做类似shell的事情(例如运行多个用;
或分隔的命令&&
),但是如果您使用的是不受信任的输入,也使您容易受到shell扩展攻击。
frequent_cron_job
命令的一个参数,试图显示它每分钟都在运行。我删除了它,因为它没有添加任何有用的信息,并引起了混乱(您的想法,如果多年来没有其他人的话)。
在shell中最好的方法是使用flock(1)
(
flock -x -w 5 99
## Do your stuff here
) 99>/path/to/my.lock
99
,>
所以是99> /...
实际上,flock -n
可以使用lckdo
* 代替*,因此您将使用内核开发人员提供的代码。
以womble的示例为基础,您将编写如下内容:
* * * * * flock -n /some/lockfile command_to_run_every_minute
BTW,看代码,所有的flock
,lockrun
和lckdo
做同样的事情,所以它只是一个问题,其中最容易提供给您。
您可以使用锁定文件。在脚本启动时创建此文件,在脚本结束时将其删除。该脚本在运行其主例程之前,应检查锁定文件是否存在,并相应地进行操作。
锁定文件由initscripts以及Unix系统中的许多其他应用程序和实用程序使用。
您尚未指定是否要脚本等待上一次运行完成。通过“我不希望作业开始彼此“堆叠””,我想您是在暗示您希望脚本在已经运行时退出,
因此,如果您不想依赖lckdo或类似的东西,可以这样做:
PIDFILE=/tmp/`basename $0`.pid
if [ -f $PIDFILE ]; then
if ps -p `cat $PIDFILE` > /dev/null 2>&1; then
echo "$0 already running!"
exit
fi
fi
echo $$ > $PIDFILE
trap 'rm -f "$PIDFILE" >/dev/null 2>&1' EXIT HUP KILL INT QUIT TERM
# do the work
我建议使用运行命令-比处理锁简单得多。从文档:
run-one是一个包装脚本,运行的脚本最多包含一个带有一组唯一参数的命令的唯一实例。当您一次只需要运行一个副本时,这对于cronjobs通常很有用。
run-this-one与run-one完全一样,不同之处在于它将使用pgrep和kill来查找和杀死用户拥有并匹配目标命令和参数的所有正在运行的进程。请注意,在尝试杀死匹配的进程时,运行本将阻塞,直到所有匹配的进程都死掉为止。
运行一恒定地运行与运行一完全相同,不同之处在于运行COMMAND退出时(零或非零)都会重新生成“ COMMAND [ARGS]”。
保持运行一次是恒定运行一次的别名。
运行一直到成功与运行一恒定运行完全相同,只是它重新生成“ COMMAND [ARGS]”,直到COMMAND成功退出(即退出零)为止。
运行一直到失败的操作与运行一不变的操作完全相同,只是它重新生成“ COMMAND [ARGS]”,直到COMMAND失败退出(即退出非零)为止。
现在systemd已经发布,Linux系统上还有另一种调度机制:
systemd.timer
在/etc/systemd/system/myjob.service
或~/.config/systemd/user/myjob.service
:
[Service]
ExecStart=/usr/local/bin/myjob
在/etc/systemd/system/myjob.timer
或~/.config/systemd/user/myjob.timer
:
[Timer]
OnCalendar=minutely
[Install]
WantedBy=timers.target
如果在下次激活计时器时服务单元已经处于激活状态,则该服务的另一个实例将不会启动。
另一种方法是,在启动时启动一次作业,每次运行结束后一分钟启动一次作业:
[Timer]
OnBootSec=1m
OnUnitInactiveSec=1m
[Install]
WantedBy=timers.target
我创建了一个jar来解决这样的问题,例如重复的cron正在运行,可能是java或shell cron。只需在Duplicates.CloseSessions(“ Demo.jar”)中传递cron名称,即可搜索并杀死该cron的existng pid(当前除外)。我已经实现了执行此操作的方法。字符串proname = ManagementFactory.getRuntimeMXBean()。getName(); 字符串pid = proname.split(“ @”)[0]; System.out.println(“当前PID:” + pid);
Process proc = Runtime.getRuntime().exec(new String[]{"bash","-c"," ps aux | grep "+cronname+" | awk '{print $2}' "});
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String s = null;
String killid="";
while ((s = stdInput.readLine()) != null ) {
if(s.equals(pid)==false)
{
killid=killid+s+" ";
}
}
然后使用shell命令再次杀死killid字符串
无论如何,@ Philip Reynolds的答案将在5秒钟的等待时间后开始执行代码,而不会获得锁定。跟随Flock似乎无法正常工作,我修改了@Philip Reynolds的答案
(
flock -w 5 -x 99 || exit 1
## Do your stuff here
) 99>/path/to/my.lock
这样就不会同时执行代码。相反,等待5秒钟后,如果到那时仍未获得锁定,则该过程将以1退出。