What's a quick-and-dirty way to make sure that only one instance of a shell script is running at a given time?
相关问题
- How to get the return code of a shell script in lu
- JQ: Select when attribute value exists in a bash a
- Invoking Mirth Connect CLI with Powershell script
- Emacs shell: save commit message
- bash print whole line after splitting line with if
相关文章
- 使用2台跳板机的情况下如何使用scp传文件
- In IntelliJ IDEA, how can I create a key binding t
- Check if directory exists on remote machine with s
- shell中反引号 `` 赋值变量问题
- How get the time in milliseconds in FreeBSD?
- Reverse four length of letters with sed in unix
- Launch interactive SSH bash session from PHP
- BASH: Basic if then and variable assignment
Simply add
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
at the beginning of your script. It's a boilerplate code from man flock. To realize how it works i wrote a script and run it simultaneously from two consoles:I have not fully realized how it works, but it seems it runs itself again using itself as a lockfile.
FLOCKER
set to"$0"
just to set some notnull reasonable value.|| :
to do nothing if something went wrong.It seems to not work on Debian 7, but seems to work back again with experimental util-linux 2.25 package. It writes "flock: ... Text file busy". It could be overridden by disabling write permission on your script.
Another option is to use shell's
noclobber
option by runningset -C
. Then>
will fail if the file already exists.In brief:
This causes the shell to call:
which atomically creates the file or fails if the file already exists.
According to a comment on BashFAQ 045, this may fail in
ksh88
, but it works in all my shells:Interesting that
pdksh
adds theO_TRUNC
flag, but obviously it's redundant:either you're creating an empty file, or you're not doing anything.
How you do the
rm
depends on how you want unclean exits to be handled.Delete on clean exit
New runs fail until the issue that caused the unclean exit to be resolved and the lockfile is manually removed.
Delete on any exit
New runs succeed provided the script is not already running.
This example is explained in the man flock, but it needs some impovements, because we should manage bugs and exit codes:
You can use another method, list processes that I used in the past. But this is more complicated that method above. You should list processes by ps, filter by its name, additional filter grep -v grep for remove parasite nad finally count it by grep -c . and compare with number. Its complicated and uncertain
When targeting a Debian machine I find the
lockfile-progs
package to be a good solution.procmail
also comes with alockfile
tool. However sometimes I am stuck with neither of these.Here's my solution which uses
mkdir
for atomic-ness and a PID file to detect stale locks. This code is currently in production on a Cygwin setup and works well.To use it simply call
exclusive_lock_require
when you need get exclusive access to something. An optional lock name parameter lets you share locks between different scripts. There's also two lower level functions (exclusive_lock_try
andexclusive_lock_retry
) should you need something more complex.I wanted to do away with lockfiles, lockdirs, special locking programs and even
pidof
since it isn't found on all Linux installations. Also wanted to have the simplest code possible (or at least as few lines as possible). Simplestif
statement, in one line:All approaches that test the existence of "lock files" are flawed.
Why? Because there is no way to check whether a file exists and create it in a single atomic action. Because of this; there is a race condition that WILL make your attempts at mutual exclusion break.
Instead, you need to use
mkdir
.mkdir
creates a directory if it doesn't exist yet, and if it does, it sets an exit code. More importantly, it does all this in a single atomic action making it perfect for this scenario.For all details, see the excellent BashFAQ: http://mywiki.wooledge.org/BashFAQ/045
If you want to take care of stale locks, fuser(1) comes in handy. The only downside here is that the operation takes about a second, so it isn't instant.
Here's a function I wrote once that solves the problem using fuser:
You can use it in a script like so:
If you don't care about portability (these solutions should work on pretty much any UNIX box), Linux' fuser(1) offers some additional options and there is also flock(1).