Solusi yang tidak memerlukan alat tambahan akan lebih disukai.
ln -s my.pid .lock
akan mengklaim kunci (diikuti oleh echo $$ > my.pid
) dan jika gagal dapat memeriksa apakah PID yang disimpan .lock
adalah benar-benar contoh aktif dari skrip
Solusi yang tidak memerlukan alat tambahan akan lebih disukai.
ln -s my.pid .lock
akan mengklaim kunci (diikuti oleh echo $$ > my.pid
) dan jika gagal dapat memeriksa apakah PID yang disimpan .lock
adalah benar-benar contoh aktif dari skrip
Jawaban:
Hampir seperti jawaban nsg: gunakan direktori kunci . Pembuatan direktori adalah atom di linux dan unix dan * BSD dan banyak OS lainnya.
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
Anda dapat memasukkan PID dari sh penguncian ke dalam file di direktori kunci untuk tujuan debugging, tetapi jangan jatuh ke dalam jebakan berpikir Anda dapat memeriksa PID tersebut untuk melihat apakah proses penguncian masih dijalankan. Banyak kondisi lomba berada di jalur itu.
mkdir
tidak atom pada NFS (yang tidak berlaku untuk saya, tapi saya kira orang harus menyebutkan bahwa, jika benar)
/tmp
mana biasanya tidak dibagikan NFS, sehingga seharusnya tidak masalah.
rm -rf
untuk menghapus direktori kunci. rmdir
akan gagal jika seseorang (belum tentu Anda) berhasil menambahkan file ke direktori.
Untuk menambah jawaban Bruce Ediger , dan terinspirasi oleh jawaban ini , Anda juga harus menambahkan lebih banyak kecerdasan ke pembersihan untuk menjaga terhadap penghentian skrip:
#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
,.
Ini mungkin terlalu sederhana, tolong perbaiki saya jika saya salah. Bukankah ini ps
cukup sederhana ?
#!/bin/bash
me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;
# do stuff below this comment
grep -v $$
. contoh nyata: lama - 14532, baru - 1453, lama - 28858, baru - 858.
grep -v $$
kegrep -v "^${$} "
grep -wv "^$$"
(lihat edit).
Saya akan menggunakan file kunci, seperti yang disebutkan oleh Marco
#!/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
lsof $0
itu tidak buruk juga?
$$
di file kunci. Kemudian sleep
untuk interval pendek dan membacanya kembali. Jika PID masih milik Anda, Anda berhasil mendapatkan kunci. Sama sekali tidak membutuhkan alat tambahan.
Jika Anda ingin memastikan bahwa hanya satu instance skrip Anda yang berjalan, lihat:
Kunci skrip Anda (terhadap menjalankan paralel)
Kalau tidak, Anda dapat memeriksa ps
atau memohon lsof <full-path-of-your-script>
, karena saya tidak akan menyebut mereka alat tambahan.
Suplemen :
sebenarnya saya berpikir untuk melakukannya seperti ini:
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
ini memastikan bahwa hanya proses dengan yang terendah pid
tetap berjalan bahkan jika Anda melakukan fork-dan-exec beberapa contoh <your_script>
secara bersamaan.
[[(lsof $0 | wc -l) > 2]] && exit
mungkin sebenarnya cukup, atau apakah ini juga rentan terhadap kondisi balapan?
Satu cara lain untuk memastikan satu contoh skrip bash berjalan:
#!/bin/bash
# Check if another instance of script is running
pidof -o %PPID -x $0 >/dev/null && echo "ERROR: Script $0 already running" && exit 1
...
pidof -o %PPID -x $0
mendapatkan PID dari skrip yang ada jika sudah berjalan atau keluar dengan kode kesalahan 1 jika tidak ada skrip lain yang berjalan
Meskipun Anda telah meminta solusi tanpa alat tambahan, ini adalah cara favorit saya menggunakan flock
:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
Ini berasal dari bagian contoh man flock
, yang selanjutnya menjelaskan:
Ini adalah kode boilerplate yang berguna untuk skrip shell. Letakkan di bagian atas skrip shell yang ingin Anda kunci dan itu akan secara otomatis mengunci sendiri pada proses pertama. Jika env var $ FLOCKER tidak disetel ke skrip shell yang sedang dijalankan, maka jalankan flock dan ambil kunci non-blocking eksklusif (menggunakan skrip itu sendiri sebagai file kunci) sebelum mengeksekusi kembali dengan argumen yang benar. Ini juga mengatur FLOCKER env var ke nilai yang benar sehingga tidak berjalan lagi.
Poin yang perlu dipertimbangkan:
flock
, skrip contoh diakhiri dengan kesalahan jika tidak dapat ditemukanLihat juga /programming/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at .
Ini adalah versi modifikasi dari Jawaban Anselmo . Idenya adalah membuat deskriptor file hanya baca menggunakan skrip bash itu sendiri dan gunakan flock
untuk menangani kunci.
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"
Perbedaan utama dari semua jawaban lain adalah bahwa kode ini tidak mengubah sistem file, menggunakan tapak yang sangat rendah dan tidak memerlukan pembersihan karena deskriptor file ditutup segera setelah skrip selesai terlepas dari status keluar. Jadi tidak masalah jika skrip gagal atau berhasil.
exec 6< "$SCRIPT"
.
Saya menggunakan cksum untuk memeriksa skrip saya benar - benar menjalankan instance tunggal, bahkan saya mengubah nama file & path file .
Saya tidak menggunakan file jebakan & kunci, karena jika server saya tiba-tiba mati, saya harus menghapus file kunci secara manual setelah server naik.
Catatan: #! / Bin / bash di baris pertama diperlukan untuk grep ps
#!/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
Atau Anda dapat melakukan hardcode cksum di dalam skrip Anda, sehingga Anda tidak perlu khawatir lagi jika Anda ingin mengubah nama file, path, atau konten skrip Anda .
#!/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
mysum
dan fsum
, ketika Anda tidak lagi berbicara tentang checksum.
Anda dapat menggunakan ini: https://github.com/sayanarijit/pidlock
sudo pip install -U pidlock
pidlock -n sleepy_script -c 'sleep 10'
Kode saya untuk Anda
#!/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}
Berdasarkan man flock
, hanya meningkatkan:
executing
Di mana saya taruh di sini sleep 10
, Anda bisa meletakkan semua skrip utama.