这个问题已经有一个答案在这里:

什么是最简单/最佳方式确保只有一个的实例,指定文本正在运行--假定这是砸在Linux上?

目前我在做:

ps -C script.name.sh > /dev/null 2>&1 || ./script.name.sh

但它有几个问题:

  1. 它将检查以外的剧本
  2. 它不会让我跑一样的脚本来自单独账户-我想的时候。
  3. -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== EXIT0, ,捕捉具体的信号是多余)在这些脚本。

在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 可能是最简单的(和最令人难忘的)变体。我用它在一定时工作的自动编码 dvdcd

# 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".

命令"我"会做两个优点。

  1. 忽略pid其是编辑编辑,如vim,因为vim编辑其映射的文件,如".文件。swp".
  2. 忽略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}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top