有什么快速而简单的方法可以确保在给定时间内只有一个shell脚本实例在运行?


当前回答

又快又脏?脚本顶部的一行代码可以工作:

[[ $(pgrep -c "`basename \"$0\"`") -gt 1 ]] && exit

当然,只要确保您的脚本名称是唯一的。:)

其他回答

一些unix具有与前面提到的flock非常相似的lockfile。

从手册中:

Lockfile可以用来创建一个 或者更多的信号量文件。如果锁, 文件不能创建所有指定的 文件(在指定的顺序),它 等待睡眠时间(默认为8) 秒并重试最后一个文件 没有成功。您可以指定 直到重试的次数 返回失败。如果数字 重试次数为-1(默认值,即 -r-1)锁文件将永远重试。

如果flock的限制,这已经在这篇文章的其他地方描述过了,对你来说不是问题,那么这应该是有效的:

#!/bin/bash

{
    # exit if we are unable to obtain a lock; this would happen if 
    # the script is already running elsewhere
    # note: -x (exclusive) is the default
    flock -n 100 || exit

    # put commands to run here
    sleep 100
} 100>/tmp/myjob.lock 

如果您不想或不能使用flock(例如,您没有使用共享文件系统),请考虑使用外部服务,如lockable。

它暴露了咨询锁原语,就像flock一样。特别地,你可以通过以下方式获取锁:

https://lockable.dev/api/acquire/my-lock-name

然后通过

https://lockable.dev/api/release/my-lock-name

通过将脚本执行与锁获取和释放结合在一起,您可以确保在任何给定时间只有一个流程实例在运行。

已经回答了一百万次了,但是另一种方式,不需要外部依赖:

LOCK_FILE="/var/lock/$(basename "$0").pid"
trap "rm -f ${LOCK_FILE}; exit" INT TERM EXIT
if [[ -f $LOCK_FILE && -d /proc/`cat $LOCK_FILE` ]]; then
   // Process already exists
   exit 1
fi
echo $$ > $LOCK_FILE

每次它将当前PID($$)写入锁文件,并在脚本启动时检查进程是否正在使用最新的PID运行。

您可以使用GNU Parallel,因为它在作为sem调用时是作为互斥量工作的。所以,具体来说,你可以使用:

sem --id SCRIPTSINGLETON yourScript

如果你也想要一个超时,使用:

sem --id SCRIPTSINGLETON --semaphoretimeout -10 yourScript

如果信号量在超时时间内没有释放,Timeout <0表示退出而不运行脚本,>的Timeout表示仍然运行脚本。

注意,您应该给它一个名称(使用——id),否则它默认为控制终端。

GNU Parallel在大多数Linux/OSX/Unix平台上是一个非常简单的安装程序——它只是一个Perl脚本。