如何确保我的 bash 脚本尚未运行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1440967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I make sure my bash script isn't already running?
提问by danb
I have a bash script I want to run every 5 minutes from cron... but there's a chance the previous run of the script isn't done yet... in this case, i want the new run to just exit. I don't want to rely on just a lock file in /tmp.. I want to make sure sure the process is actually running before i honor the lock file (or whatever)...
我有一个 bash 脚本,我想从 cron 开始每 5 分钟运行一次......但是有可能脚本的上一次运行还没有完成......在这种情况下,我希望新的运行退出。我不想只依赖 /tmp 中的锁定文件.. 我想确保在我兑现锁定文件(或其他)之前该进程实际上正在运行......
Here is what I have stolen from the internet so far... how do i smarten it up a bit? or is there a completely different way that's better?
到目前为止,这是我从互联网上窃取的内容......我如何让它变得更聪明一点?或者有没有更好的完全不同的方式?
if [ -f /tmp/mylockFile ] ; then
echo 'Script is still running'
else
echo 1 > /tmp/mylockFile
/* Do some stuff */
rm -f /tmp/mylockFile
fi
回答by DigitalRoss
# Use a lockfile containing the pid of the running process
# If script crashes and leaves lockfile around, it will have a different pid so
# will not prevent script running again.
#
lf=/tmp/pidLockFile
# create empty lock file if none exists
cat /dev/null >> $lf
read lastPID < $lf
# if lastPID is not null and a process with that pid exists , exit
[ ! -z "$lastPID" -a -d /proc/$lastPID ] && exit
echo not running
# save my pid in the lock file
echo $$ > $lf
# sleep just to make testing easier
sleep 5
There is at least one race condition in this script. Don't use it for a life support system, lol. But it should work fine for your example, because your environment doesn't start two scripts simultaneously. There are lots of ways to use more atomic locks, but they generally depend on having a particular thing optionally installed, or work differently on NFS, etc...
此脚本中至少有一个竞争条件。不要将它用于生命维持系统,哈哈。但它应该适用于您的示例,因为您的环境不会同时启动两个脚本。有很多方法可以使用更多的原子锁,但它们通常取决于是否安装了特定的东西,或者在 NFS 上以不同的方式工作,等等......
回答by kali
You might want to have a look at the man page for the flockcommand, if you're lucky enough to get it on your distribution.
flock如果您有幸在您的发行版中获得它,您可能想查看该命令的手册页。
NAME
flock - Manage locks from shell scripts
SYNOPSIS
flock [-sxon] [-w timeout] lockfile [-c] command...
回答by Gunstick
Never use a lock filealways use a lock directory. In your specific case, it's not so important because the start of the script is scheduled in 5min intervals. But if you ever reuse this code for a webserver cgi-script you are toast.
永远不要使用锁文件总是使用锁目录。在您的特定情况下,这并不重要,因为脚本的启动间隔为 5 分钟。但是,如果您曾经将此代码重用于网络服务器 cgi 脚本,那么您就是敬酒。
if mkdir /tmp/my_lock_dir 2>/dev/null
then
echo "running now the script"
sleep 10
rmdir /tmp/my_lock_dir
fi
This has a problem if you have a stale lock, means the lock is there but no associated process. Your cron will never run.
如果您有一个陈旧的锁,这会出现问题,这意味着锁在那里但没有关联的进程。你的 cron 永远不会运行。
Why use a directory? Because mkdir is an atomic operation. Only one process at a time can create a directory, all other processes get an error. This even works across shared filesystems and probably even between different OS types.
为什么要使用目录?因为 mkdir 是一个原子操作。一次只有一个进程可以创建目录,所有其他进程都会出错。这甚至适用于共享文件系统,甚至可能适用于不同的操作系统类型。
回答by ire_and_curses
If you want to check the process's existence, just look at the output of
如果要检查进程是否存在,只需查看以下输出
ps aux | grep your_script_name
ps aux | grep your_script_name
If it's there, it's not dead...
如果它在那里,它就不会死......
As pointed out in the comments and other answers, using the PID stored in the lockfile is much safer and is the standard approach most apps take. I just do this because it's convenient and I almost never see the corner cases (e.g. editing the file when the cronexecutes) in practice.
正如评论和其他答案中指出的那样,使用存储在锁定文件中的 PID 更安全,并且是大多数应用程序采用的标准方法。我这样做只是因为它很方便,而且cron在实践中我几乎从未见过极端情况(例如,在执行时编辑文件)。
回答by P Shved
Store your pid in mylockFile. When you need to check, look up ps for the process with the pid you read from file. If it exists, your script is running.
将您的 pid 存储在mylockFile. 当您需要检查时,使用您从文件中读取的 pid 查找进程的 ps。如果存在,则您的脚本正在运行。
回答by Robert
If you use a lockfile, you should make sure that the lockfile is always removed. You can do this with 'trap':
如果使用锁定文件,则应确保始终删除锁定文件。你可以用“陷阱”来做到这一点:
if ( set -o noclobber; echo "locked" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
echo "Locking succeeded" >&2
rm -f "$lockfile"
else
echo "Lock failed - exit" >&2
exit 1
fi
The noclobber option makes the creation of lockfile atomic, like using a directory.
noclobber 选项使锁定文件的创建具有原子性,就像使用目录一样。
回答by MoonCactus
As a one-liner and if you do not want to use a lockfile (e.g. b/c/ of a read only filesystem, etc)
作为单行程序,如果您不想使用锁文件(例如只读文件系统的 b/c/ 等)
test "$(pidof -x $(basename [[ "$(pidof -x $(basename COMMAND_LINE="JOBS=$(sh -c "ps axo pid,command | grep \"${COMMAND_LINE}\" | grep -v grep | grep -v $$")
$*"
JOBS=$(SUBSHELL_PID=$BASHPID; ps axo pid,command | grep "${COMMAND_LINE}" | grep -v $$ | g rep -v ${SUBSHELL_PID} | grep -v grep)
if [[ -z "${JOBS}" ]]
then
# not already running
else
# already running
fi
))" != $$ ]] && exit
))" != $$ && exit
It checks that the full list of PID that bear the name of your script is equal to the current PID. The "-x" also checks for the name of shell scripts.
它检查带有脚本名称的 PID 的完整列表是否等于当前的 PID。“-x”还检查 shell 脚本的名称。
Bash makes it even shorter and faster:
Bash 让它变得更短、更快:
pgrep -f "/bin/\w*sh .*scriptname" | grep -vq $$ && exit
回答by starfry
I was trying to solve this problem today and I came up with the below:
我今天试图解决这个问题,我想出了以下内容:
##代码##This relies on $BASHPIDwhich contains the PID inside a subshell ($$in the subshell is the parent pid). However, this relies on Bash v4 and I needed to run this on OSX which has Bash v3.2.48. I ultimately came up with another solution and it is cleaner:
这取决于$BASHPID哪个包含子外壳内的 PID($$子外壳中是父 pid)。但是,这依赖于 Bash v4,我需要在具有 Bash v3.2.48 的 OSX 上运行它。我最终想出了另一个解决方案,它更干净:
回答by Paused until further notice.
In some cases, you might want to be able to distinguish between who is running the script and allow some concurrency but not all. In that case, you can use per-user, per-tty or cron-specific locks.
在某些情况下,您可能希望能够区分谁在运行脚本并允许一些并发但不是全部。在这种情况下,您可以使用每个用户、每个 tty 或特定于 cron 的锁。
You can use environment variables such as $USER or the output of a program such as ttyto create the filename. For cron, you can set a variable in the crontabfile and test for it in your script.
您可以使用环境变量(例如 $USER)或程序的输出(例如tty创建文件名)。对于cron,您可以在crontab文件中设置一个变量并在脚本中对其进行测试。
回答by Francois Scheurer
you can use this one:
你可以使用这个:
##代码##
