追加のツールを必要としないソリューションが推奨されます。
ln -s my.pid .lock
ロックを要求します(続くecho $$ > my.pid
)、失敗にに保存されているPIDがいるかどうかを確認することができ.lock
、本当にスクリプトのアクティブなインスタンスである
追加のツールを必要としないソリューションが推奨されます。
ln -s my.pid .lock
ロックを要求します(続くecho $$ > my.pid
)、失敗にに保存されているPIDがいるかどうかを確認することができ.lock
、本当にスクリプトのアクティブなインスタンスである
回答:
nsgの答えとほぼ同じ:ロックディレクトリを使用します。ディレクトリの作成は、linux、unix、* BSD、および他の多くのOSでアトミックです。
if mkdir $LOCKDIR
then
# Do important, exclusive stuff
if rmdir $LOCKDIR
then
echo "Victory is mine"
else
echo "Could not remove lock dir" >&2
fi
else
# Handle error condition
...
fi
デバッグのために、ロックするshのPIDをロックディレクトリのファイルに入れることができますが、そのPIDをチェックしてロックプロセスがまだ実行されているかどうかを確認できるとは思わないでください。多くの競合状態がその道をたどります。
mkdir
NFS上のアトミックではありません(私の場合ではないですが、私は、人はそれを言及する必要があります推測する場合はtrue)
rm -rf
ロックディレクトリを削除するために使用します。rmdir
誰か(必ずしもあなたではない)がファイルをディレクトリに追加できた場合は失敗します。
Bruce Edigerの回答に追加し、この回答に触発されて、スクリプトの終了を防ぐためにクリーンアップにさらにスマートを追加する必要があります。
#Remove the lock directory
function cleanup {
if rmdir $LOCKDIR; then
echo "Finished"
else
echo "Failed to remove lock directory '$LOCKDIR'"
exit 1
fi
}
if mkdir $LOCKDIR; then
#Ensure that if we "grabbed a lock", we release it
#Works for SIGTERM and SIGINT(Ctrl-C)
trap "cleanup" EXIT
echo "Acquired lock, running"
# Processing starts here
else
echo "Could not create lock directory '$LOCKDIR'"
exit 1
fi
if ! mkdir "$LOCKDIR"; then handle failure to lock and exit; fi trap and do processing after if-statement
。
これはあまりにも単純すぎるかもしれません。間違っている場合は修正してください。単純ではありませんps
か?
#!/bin/bash
me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;
# do stuff below this comment
grep -v $$
ます 実際の例:古い- 14532、新しい- 1453年、旧- 28858、新しい- 858
grep -v $$
して修正しましたgrep -v "^${$} "
grep -wv "^$$"
(編集を参照)。
マルコが述べたように、ロックファイルを使用します
#!/bin/bash
# Exit if /tmp/lock.file exists
[ -f /tmp/lock.file ] && exit
# Create lock file, sleep 1 sec and verify lock
echo $$ > /tmp/lock.file
sleep 1
[ "x$(cat /tmp/lock.file)" == "x"$$ ] || exit
# Do stuff
sleep 60
# Remove lock file
rm /tmp/lock.file
$$
ロックファイルに書き込みを行うことにより、競合状態を減らすことができます。その後sleep
、短い間隔で、それを読み返します。PIDがまだ自分のものである場合は、ロックを正常に取得しています。追加のツールはまったく必要ありません。
スクリプトの1つのインスタンスのみが実行されていることを確認する場合は、以下をご覧ください。
それ以外の場合は、追加のツールとは呼ばないps
ためlsof <full-path-of-your-script>
、チェックまたは起動できます。
補足:
実際に私はこのようにすることを考えました:
for LINE in `lsof -c <your_script> -F p`; do
if [ $$ -gt ${LINE#?} ] ; then
echo "'$0' is already running" 1>&2
exit 1;
fi
done
これにより、pid
複数のインスタンスを<your_script>
同時にfork-execした場合でも、最低のプロセスのみが実行され続けます。
[[(lsof $0 | wc -l) > 2]] && exit
かもしれないが、実際には十分であるか、またはこれはまた、競合状態になりやすいのですか?
追加のツールなしで解決策を求めてきましたが、これは私が使用する私のお気に入りの方法flock
です:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
これはの例のセクションから来ていman flock
ます。
これは、シェルスクリプトの便利な定型コードです。ロックするシェルスクリプトの先頭に配置すると、最初の実行時に自動的にロックされます。実行されているシェルスクリプトにenv var $ FLOCKERが設定されていない場合、flockを実行し、適切な引数で再実行する前に排他的な非ブロックロックを取得します(ロックファイルとしてスクリプト自体を使用)。また、FLOCKER env varを正しい値に設定して、再度実行されないようにします。
考慮すべき点:
flock
。見つからない場合、サンプルスクリプトはエラーで終了します/programming/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-atも参照してください。
これは、Anselmo's Answerの修正版です。アイデアは、bashスクリプト自体を使用flock
して読み取り専用ファイル記述子を作成し、ロックの処理に使用することです。
SCRIPT=`realpath $0` # get absolute path to the script itself
exec 6< "$SCRIPT" # open bash script using file descriptor 6
flock -n 6 || { echo "ERROR: script is already running" && exit 1; } # lock file descriptor 6 OR show error message if script is already running
echo "Run your single instance code here"
他のすべての答えとの主な違いは、このコードはファイルシステムを変更せず、非常に低いフットプリントを使用し、スクリプトが終了状態に関係なく終了するとすぐにファイル記述子が閉じられるため、クリーンアップを必要としないことです。したがって、スクリプトが失敗するか成功するかは問題ではありません。
exec 6< "$SCRIPT"
。
cksumを使用して、ファイル名とファイルパスを変更しても、スクリプトが本当に単一のインスタンスを実行していることを確認しています。
サーバーが突然ダウンした場合、サーバーが起動した後に手動でロックファイルを削除する必要があるため、トラップとロックファイルを使用していません。
注:grep psには、最初の行の#!/ bin / bashが必要です
#!/bin/bash
checkinstance(){
nprog=0
mysum=$(cksum $0|awk '{print $1}')
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(cksum /proc/$i/cwd/$cmd|awk '{print $1}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
または、スクリプト内でcksumをハードコーディングできるので、スクリプトのファイル名、パス、またはコンテンツを変更する場合に心配する必要はありません。
#!/bin/bash
mysum=1174212411
checkinstance(){
nprog=0
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(grep mysum /proc/$i/cwd/$cmd|head -1|awk -F= '{print $2}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
これを使用できます:https : //github.com/sayanarijit/pidlock
sudo pip install -U pidlock
pidlock -n sleepy_script -c 'sleep 10'
あなたへの私のコード
#!/bin/bash
script_file="$(/bin/readlink -f $0)"
lock_file=${script_file////_}
function executing {
echo "'${script_file}' already executing"
exit 1
}
(
flock -n 9 || executing
sleep 10
) 9> /var/lock/${lock_file}
に基づいてman flock
、改善のみ:
executing
ここにを配置するとsleep 10
、すべてのメインスクリプトを配置できます。