我想创建一个只能在任何时候运行一次的sh脚本。
说,如果我执行脚本,那么我再次执行脚本,如何使脚本如果脚本的第一个exec仍在工作,第二个脚本将失败并出现错误。即在做任何事情之前,我需要检查脚本是否在其他地方运行。我该怎么做呢?
我运行的脚本运行时间很长(即永远运行)。我想使用像cron之类的东西每隔15分钟调用一次脚本,这样如果进程失败,它将由下一个cron运行脚本重新启动。
答案 0 :(得分:15)
你想要一个pid文件,可能是这样的:
pidfile=/path/to/pidfile
if [ -f "$pidfile" ] && kill -0 `cat $pidfile` 2>/dev/null; then
echo still running
exit 1
fi
echo $$ > $pidfile
答案 1 :(得分:9)
我认为你需要使用lockfile命令。请参阅using lockfiles in shell scripts (BASH)或http://www.davidpashley.com/articles/writing-robust-shell-scripts.html。
第二篇文章使用“手工制作的锁文件”,并展示如何捕获脚本终止&amp;释放锁;虽然在大多数情况下使用lockfile -l <timeout seconds>
可能是一个很好的选择。
没有超时的使用示例:
lockfile script.lock
<do some stuff>
rm -f script.lock
确保在此期间启动的任何第二个脚本将无限期地等待文件被删除,然后再继续。
如果我们知道脚本的运行时间不应超过X秒,并且script.lock
仍然存在,则可能意味着脚本的先前实例在删除script.lock
之前被终止。在这种情况下,我们可以告诉lockfile
在超时后强制重新创建锁(X = 10以下):
lockfile -l 10 /tmp/mylockfile
<do some stuff>
rm -f /tmp/mylockfile
由于lockfile
可以创建多个锁定文件,因此有一个参数可指导它在重试获取所需的下一个文件(-<sleep before retry, seconds>
和-r <number of retries>
)之前应等待多长时间。强制删除锁定时,还有一个参数-s <suspend seconds>
用于等待时间(这种补充是强制破解锁定之前等待的超时时间)。
答案 2 :(得分:2)
将进程ID写入文件,然后在新实例启动时,检查文件以查看旧实例是否仍在运行。
答案 3 :(得分:2)
(
if flock -n 9
then
echo 'Not doing the critical operation (lock present).'
exit;
fi
# critical section goes here
) 9>'/run/lock/some_lock_file'
rm -f '/run/lock/some_lock_file'
来自flock(1)手册页中的示例。在shell脚本中使用非常实用。
答案 4 :(得分:1)
您可以使用run-one
包,该包提供run-one
,run-this-one
和keep-one-running
。
套餐:https://launchpad.net/ubuntu/+source/run-one
介绍它的博客:http://blog.dustinkirkland.com/2011/02/introducing-run-one-and-run-this-one.html
答案 5 :(得分:0)
我刚写了一个工具来做到这一点: https://github.com/ORESoftware/quicklock
写一个好的一个需要大约15个loc,所以不想要包含在每个shell脚本中。基本上是这样的:
$ ql_acquire_lock
以上调用此bash函数:
function ql_acquire_lock {
set -e;
name="${1:-$PWD}" # the lock name is the first argument, if that is empty, then set the lockname to $PWD
mkdir -p "$HOME/.quicklock/locks"
fle=$(echo "${name}" | tr "/" _)
qln="$HOME/.quicklock/locks/${fle}.lock"
mkdir "${qln}" &> /dev/null || { echo "${ql_magenta}quicklock: could not acquire lock with name '${qln}'${ql_no_color}."; exit 1; }
export quicklock_name="${qln}"; # export the var *only if* above mkdir command succeeds
trap on_ql_trap EXIT;
}
当脚本退出时,它会使用陷阱
自动释放锁定function on_ql_trap {
echo "quicklock: process with pid $$ was trapped.";
ql_release_lock
}
要随意手动释放锁定,请使用ql_release_lock
:
function ql_maybe_fail {
if [[ "$1" == "true" ]]; then
echo -e "${ql_magenta}quicklock: exiting with 1 since fail flag was set for your 'ql_release_lock' command.${ql_no_color}"
exit 1;
fi
}
function ql_release_lock () {
if [[ -z "${quicklock_name}" ]]; then
echo -e "quicklock: no lockname was defined. (\$quicklock_name was not set).";
ql_maybe_fail "$1";
return 0;
fi
if [[ "$HOME" == "${quicklock_name}" ]]; then
echo -e "quicklock: dangerous value set for \$quicklock_name variable..was equal to user home directory, not good.";
ql_maybe_fail "$1"
return 0;
fi
rm -r "${quicklock_name}" &> /dev/null &&
{ echo -e "quicklock: lock with name '${quicklock_name}' was released."; } ||
{ echo -e "quicklock: no lock existed for lockname '${quicklock_name}'."; ql_maybe_fail "$1"; }
trap - EXIT # clear/unset trap
}