crontab 経由でコマンドを実行するときなど、コマンドの二重起動を抑止したいことがしばしばあります。
二重起動を抑止するコマンドとしては、 Linux で util-linux パッケージが使えれば flock コマンド、それ以外 (macOS とか) では自力でスクリプトを組むか、こちらで紹介されている setlock を使うことになると思います。
setlock は美しいツールだなーと思うのですが、daemontools をソースからビルドする必要があり、一手間かかります。なんというかコンパイルとかせずにどうにかならないものか...。
と思いまして setlock.c のソース を見たところ、超短いソースだったので、 Ruby に移植してみました。Amazon AMI には ruby-2.0 が最初から入ってるから、これならパスの通ったところにコピペで置くだけっ...。
setlock.rb
#!/usr/bin/env ruby
require 'optparse'
Version = '1.0.0'
flagx = false
flagndelay = false
parser = OptionParser.new
parser.banner = "Usage: setlock.rb [ -nNxX ] file program [ arg ... ]"
parser.on('-n','No delay. If fn is locked by another process, setlock gives up.'){|v|flagndelay=v}
parser.on('-N','(Default.) Delay. If fn is locked by another process, setlock waits until it can obtain a new lock.'){|v|flagndelay=!v}
parser.on('-x','If fn cannot be opened (or created) or locked, setlock exits zero.'){|v|flagx=v}
parser.on('-X','(Default.) If fn cannot be opened (or created) or locked, setlock prints an error message and exits nonzero.'){|v|flagx=!v}
parser.summary_width=3
begin
parser.parse!(ARGV)
rescue => e
abort "#{e.message}"
end
lockfile = ARGV.shift
abort "missing argument.\n#{parser.help}" if ARGV.size == 0
f = nil
begin
f = File.open(lockfile, 'w')
rescue => e
exit 0 if flagx
abort "unable to open #{lockfile}"
end
if not f.flock(flagndelay ? (File::LOCK_EX|File::LOCK_NB) : File::LOCK_EX)
exit 0 if flagx
abort "unable to lock #{lockfile}"
end
system ARGV[0], *ARGV[1..-1]
exit $?.exitstatus
とはいえ、システム系プログラムはそんなに得意でないのと、Ruby あまり詳しくないので、変だったらぜひコメントで教えて下さい。それ以前に実は このパッケージ入れたら setlock 含まれてるよとか、あったらショックですが...。