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


当前回答

如果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(如上所述,例如by presto8)来实现计数信号量。它支持您想要的任意数量的并发进程。我们使用它来限制各种队列工作者进程的并发级别。

它很像sem,但重量轻得多。(完全披露:我是在发现sem对我们的需求来说太繁重了,而且没有一个简单的计数信号量实用程序可用后写的。)

这个例子是在man flock中解释的,但它需要一些改进,因为我们应该管理bug和退出代码:

   #!/bin/bash
   #set -e this is useful only for very stupid scripts because script fails when anything command exits with status more than 0 !! without possibility for capture exit codes. not all commands exits >0 are failed.

( #start subprocess
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200
  if [ "$?" != "0" ]; then echo Cannot lock!; exit 1; fi
  echo $$>>/var/lock/.myscript.exclusivelock #for backward lockdir compatibility, notice this command is executed AFTER command bottom  ) 200>/var/lock/.myscript.exclusivelock.
  # Do stuff
  # you can properly manage exit codes with multiple command and process algorithm.
  # I suggest throw this all to external procedure than can properly handle exit X commands

) 200>/var/lock/.myscript.exclusivelock   #exit subprocess

FLOCKEXIT=$?  #save exitcode status
    #do some finish commands

exit $FLOCKEXIT   #return properly exitcode, may be usefull inside external scripts

你可以用另一种方法,列出我过去用过的过程。但这比上面的方法要复杂得多。你应该按ps列出进程,按其名称过滤,附加过滤器grep -v grep清除寄生虫,最后按grep -c计数。和数字比较。这是复杂而不确定的

这个我在任何地方都没有发现,它使用read,我不确切地知道read是否实际上是原子的,但到目前为止它对我来说很有用……它很有趣,因为它只是bash内置的,这是一个进程内实现,你启动locker协进程并使用它的I / O来管理锁,同样可以在进程间完成,只需将目标I / O从locker文件描述符交换到文件系统上的文件描述符(exec 3<>/file && exec 4</file)

## gives locks
locker() {
    locked=false
    while read l; do
        case "$l" in
            lock)
                if $locked; then
                    echo false
                else
                    locked=true
                    echo true
                fi
                ;;
            unlock)
                if $locked; then
                    locked=false
                    echo true
                else
                    echo false
                fi
                ;;
            *)
                echo false
                ;;
        esac
    done
}
## locks
lock() {
    local response
    echo lock >&${locker[1]}
    read -ru ${locker[0]} response
    $response && return 0 || return 1
}

## unlocks
unlock() {
    local response
    echo unlock >&${locker[1]}
    read -ru ${locker[0]} response
    $response && return 0 || return 1
}

在flock(2)系统调用周围有一个包装器,毫无想象力地称为flock(1)。这使得可靠地获得独占锁相对容易,而不必担心清理等问题。手册页上有一些关于如何在shell脚本中使用它的示例。

如果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