什么是最好的方式确保只有一个实例的庆典脚本是运行?[重复]
题
这个问题已经有一个答案在这里:
什么是最简单/最佳方式确保只有一个的实例,指定文本正在运行--假定这是砸在Linux上?
目前我在做:
ps -C script.name.sh > /dev/null 2>&1 || ./script.name.sh
但它有几个问题:
- 它将检查以外的剧本
- 它不会让我跑一样的脚本来自单独账户-我想的时候。
-C
仅检查第14字的进程名称
当然,我可以写我自己的pidfile处理,但我觉得应该有一个简单的方式来做到这一点。
解决方案
如果剧本是一样的所有的用户,可以使用 lockfile
办法。如果你获得锁,继续执别显示的消息和出口。
作为一个例子:
[Terminal #1] $ lockfile -r 0 /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] lockfile: Sorry, giving up on "/tmp/the.lock"
[Terminal #1] $ rm -f /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] $
后 /tmp/the.lock
已经取得的脚本中将唯一一个获执行。当你做,只是删除了锁。在脚本形成,这可能看起来像:
#!/bin/bash
lockfile -r 0 /tmp/the.lock || exit 1
# Do stuff here
rm -f /tmp/the.lock
其他提示
咨询锁已使用的年龄,它可以用在砸向脚本。我喜欢简单的 flock
(从 util-linux[-ng]
)过 lockfile
(从 procmail
).并且永远记住关于一个陷阱在退出(sigspec== EXIT
或 0
, ,捕捉具体的信号是多余)在这些脚本。
在2009年,我发布了我的带锁的脚本样本(原文可以在我的wiki网页,如今可作为 要点).转变成一个实例-的每用户是微不足道的。使用它,你也可以很容易地编写脚本用于其他方案需要一些锁定或同步。
这里所提到的样板为了您的方便。
#!/bin/bash
# SPDX-License-Identifier: MIT
## Copyright (C) 2009 Przemyslaw Pawelczyk <przemoc@gmail.com>
##
## This script is licensed under the terms of the MIT license.
## https://opensource.org/licenses/MIT
#
# Lockable script boilerplate
### HEADER ###
LOCKFILE="/var/lock/`basename $0`"
LOCKFD=99
# PRIVATE
_lock() { flock -$1 $LOCKFD; }
_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; }
_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; }
# ON START
_prepare_locking
# PUBLIC
exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail
exlock() { _lock x; } # obtain an exclusive lock
shlock() { _lock s; } # obtain a shared lock
unlock() { _lock u; } # drop a lock
### BEGIN OF SCRIPT ###
# Simplest example is avoiding running multiple instances of script.
exlock_now || exit 1
# Remember! Lock file is removed when one of the scripts exits and it is
# the only script holding the lock or lock is not acquired at all.
我认为 flock
可能是最简单的(和最令人难忘的)变体。我用它在一定时工作的自动编码 dvd 和 cd
# try to run a command, but fail immediately if it's already running
flock -n /var/lock/myjob.lock my_bash_command
使用 -w
对于超时或离开出的选项,以等待,直到的锁被释放。最后,人页显示了一个很好的例为多个命令:
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
使用 set -o noclobber
选项,并尝试,以复盖共同的文件。
一个简短的例子
if ! (set -o noclobber ; echo > /tmp/global.lock) ; then
exit 1 # the global.lock already exists
fi
# ... remainder of script ...
一个较长的实例
这个例子将等待 global.lock
文件但后超时太长。
function lockfile_waithold()
{
declare -ir time_beg=$(date '+%s')
declare -ir time_max=7140 # 7140 s = 1 hour 59 min.
# poll for lock file up to ${time_max}s
# put debugging info in lock file in case of issues ...
while ! \
(set -o noclobber ; \
echo -e "DATE:$(date)\nUSER:$(whoami)\nPID:$$" > /tmp/global.lock \
) 2>/dev/null
do
if [ $(($(date '+%s') - ${time_beg})) -gt ${time_max} ] ; then
echo "Error: waited too long for lock file /tmp/global.lock" 1>&2
return 1
fi
sleep 1
done
return 0
}
function lockfile_release()
{
rm -f /tmp/global.lock
}
if ! lockfile_waithold ; then
exit 1
fi
trap lockfile_release EXIT
# ... remainder of script ...
(这是类似于 这个职位 通过@巴里*凯利这是注意到,之后。)
我不知道有任何一个行稳健的方案, 所以你可能最终滚你自己的。
Lockfiles是不完美的,但小于使用'ps|查询|查询-v'管道。
说到这,你也许会考虑保持过程的控制 分开你的脚-有一个开始脚本。或者,至少因素它的职能保持在一个单独的文件, 所以,你可能在叫脚本有:
. my_script_control.ksh
# Function exits if cannot start due to lockfile or prior running instance.
my_start_me_up lockfile_name;
trap "rm -f $lockfile_name; exit" 0 2 3 15
在每一个脚本需求的控制的逻辑。的 陷阱 确保文件锁被删除时的呼叫者退出, 所以你没有代码本上每个出口点在脚本。
使用一个单独控制的脚本意味着你可以检查的边缘情况:删除陈旧的日志文件,验证的文件锁相关的是正确的
目前的运行实例脚本,给予一种选择杀死的运行过程中,等等。这也意味着你已经有了一个更好的机会使用牛瘟很忙 ps
输出成功。Ps-查询可用于验证文件锁具有正在运行过程中与它相关联。也许你可以命名你的lockfiles在一些方式包括信息有关的过程:用户,pid等, 它可以用通过一个脚本后来援引,以决定是否进程
创建该文件锁仍然左右。
第一个试验例
[[ $(lsof -t $0| wc -l) > 1 ]] && echo "At least one of $0 is running"
第二个试验例
currsh=$0
currpid=$$
runpid=$(lsof -t $currsh| paste -s -d " ")
if [[ $runpid == $currpid ]]
then
sleep 11111111111111111
else
echo -e "\nPID($runpid)($currpid) ::: At least one of \"$currsh\" is running !!!\n"
false
exit 1
fi
解释
"我-t"列出所有pid的当前运行的脚本名为"$0".
命令"我"会做两个优点。
- 忽略pid其是编辑编辑,如vim,因为vim编辑其映射的文件,如".文件。swp".
- 忽略pid叉通过目前的运行壳脚本,其中大部分"查询的"衍生物的命令不能实现这一目标。使用"pstree-pH pidnum"命令详情参见关于当前进程的同振状态。
我发现这procmail包的依赖:
apt install liblockfile-bin
运行:dotlockfile -l file.lock
文件。锁定会被创建。
解锁:dotlockfile -u file.lock
使用这种名单这一包文件/命令:
dpkg-query -L liblockfile-bin
Ubuntu/Debian发布有 start-stop-daemon
工具,它是针对同一目的,你描述。也参看 /etc/init。d/骨架 看看它是如何使用的书面启动/停止的脚本。
--诺亚
我还建议寻找 chpst (第一部分的runit):
chpst -L /tmp/your-lockfile.loc ./script.name.sh
一个行最终的解决方案:
[ "$(pgrep -fn $0)" -ne "$(pgrep -fo $0)" ] && echo "At least 2 copies of $0 are running"
我有同样的问题,并提出了一个 模板 使用的文件锁,pid文件,举行过程中身份证号码和一个 kill -0 $(cat $pid_file)
检查中止脚本没有停止下运行。这将创建一个foobar-$USERID文件夹/tmp那里的文件锁和pid文件的生活。
你仍然可以调用的剧本和做其他的事,只要你保持这些行动在 alertRunningPS
.
#!/bin/bash
user_id_num=$(id -u)
pid_file="/tmp/foobar-$user_id_num/foobar-$user_id_num.pid"
lock_file="/tmp/foobar-$user_id_num/running.lock"
ps_id=$$
function alertRunningPS () {
local PID=$(cat "$pid_file" 2> /dev/null)
echo "Lockfile present. ps id file: $PID"
echo "Checking if process is actually running or something left over from crash..."
if kill -0 $PID 2> /dev/null; then
echo "Already running, exiting"
exit 1
else
echo "Not running, removing lock and continuing"
rm -f "$lock_file"
lockfile -r 0 "$lock_file"
fi
}
echo "Hello, checking some stuff before locking stuff"
# Lock further operations to one process
mkdir -p /tmp/foobar-$user_id_num
lockfile -r 0 "$lock_file" || alertRunningPS
# Do stuff here
echo -n $ps_id > "$pid_file"
echo "Running stuff in ONE ps"
sleep 30s
rm -f "$lock_file"
rm -f "$pid_file"
exit 0
我发现了一个相当简单的方法来处理"一份脚本每系统"。它不允许我多份脚本来自许多帐户,虽然(对标准的Linux)。
方案:
在开始脚本,我给了:
pidof -s -o '%PPID' -x $( basename $0 ) > /dev/null 2>&1 && exit
显然 pidof 伟大的作品中一种方法是:
- 它没有限制程序的名字
ps -C ...
- 它不需要我来做
grep -v grep
(或任何类似的东西)
它不依赖于lockfiles,这对我来说是一个巨大的胜利,因为中转对他们意味着你必须加处理的陈旧lockfiles-这是不是真的很复杂,但是如果可以避免的-为什么不呢?
作为检查用"一份脚本每运行用户",我写了这个,但我不太满意:
(
pidof -s -o '%PPID' -x $( basename $0 ) | tr ' ' '\n'
ps xo pid= | tr -cd '[0-9\n]'
) | sort | uniq -d
然后我检查其输出-如果它是空的-有没有一份脚本来自相同的用户。
从你的脚本:
ps -ef | grep $0 | grep $(whoami)
这里是我们的标准点。它可以恢复从脚本不知何故死亡没有清理它的文件锁.
它写进程ID锁的文件,如果它运行正常。如果找到锁的文件时,它开始运行,它将宣读的过程ID从锁的文件和检查,如果这一进程的存在。如果处理不存在的,它将消除陈旧锁的文件并进行。并且只有如果锁定文件是否存在和该进程仍在运行,它将退出。和它写入一条消息时,它的出口。
# lock to ensure we don't get two copies of the same job
script_name="myscript.sh"
lock="/var/run/${script_name}.pid"
if [[ -e "${lock}" ]]; then
pid=$(cat ${lock})
if [[ -e /proc/${pid} ]]; then
echo "${script_name}: Process ${pid} is still running, exiting."
exit 1
else
# Clean up previous lock file
rm -f ${lock}
fi
fi
trap "rm -f ${lock}; exit $?" INT TERM EXIT
# write $$ (PID) to the lock file
echo "$$" > ${lock}