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
Here's an implementation that uses a lockfile and echoes a PID into it. This serves as a protection if the process is killed before removing the pidfile:
The trick here is the
kill -0
which doesn't deliver any signal but just checks if a process with the given PID exists. Also the call totrap
will ensure that the lockfile is removed even when your process is killed (exceptkill -9
).Here's an approach that combines atomic directory locking with a check for stale lock via PID and restart if stale. Also, this does not rely on any bashisms.
I find that bmdhack's solution is the most practical, at least for my use case. Using flock and lockfile rely on removing the lockfile using rm when the script terminates, which can't always be guaranteed (e.g., kill -9).
I would change one minor thing about bmdhack's solution: It makes a point of removing the lock file, without stating that this is unnecessary for the safe working of this semaphore. His use of kill -0 ensures that an old lockfile for a dead process will simply be ignored/over-written.
My simplified solution is therefore to simply add the following to the top of your singleton:
Of course, this script still has the flaw that processes that are likely to start at the same time have a race hazard, as the lock test and set operations are not a single atomic action. But the proposed solution for this by lhunath to use mkdir has the flaw that a killed script may leave behind the directory, thus preventing other instances from running.
You can use
GNU Parallel
for this as it works as a mutex when called assem
. So, in concrete terms, you can use:If you want a timeout too, use:
Timeout of <0 means exit without running script if semaphore is not released within the timeout, timeout of >0 mean run the script anyway.
Note that you should give it a name (with
--id
) else it defaults to the controlling terminal.GNU Parallel
is a very simple install on most Linux/OSX/Unix platforms - it is just a Perl script.There's a wrapper around the flock(2) system call called, unimaginatively, flock(1). This makes it relatively easy to reliably obtain exclusive locks without worrying about cleanup etc. There are examples on the man page as to how to use it in a shell script.
For shell scripts, I tend to go with the
mkdir
overflock
as it makes the locks more portable.Either way, using
set -e
isn't enough. That only exits the script if any command fails. Your locks will still be left behind.For proper lock cleanup, you really should set your traps to something like this psuedo code (lifted, simplified and untested but from actively used scripts) :
Here's what will happen. All traps will produce an exit so the function
__sig_exit
will always happen (barring a SIGKILL) which cleans up your locks.Note: my exit values are not low values. Why? Various batch processing systems make or have expectations of the numbers 0 through 31. Setting them to something else, I can have my scripts and batch streams react accordingly to the previous batch job or script.