Untuk penggunaan aktual, Anda harus menggunakan jawaban terpilih teratas .
Namun, saya ingin membahas beberapa pendekatan yang rusak dan semi-bisa diterapkan menggunakan ps
dan banyak peringatan yang mereka miliki, karena saya terus melihat orang menggunakannya.
Jawaban ini benar-benar jawaban untuk "Mengapa tidak menggunakan ps
dan grep
menangani penguncian di shell?"
Pendekatan yang rusak # 1
Pertama, pendekatan yang diberikan dalam jawaban lain yang memiliki beberapa upvotes terlepas dari kenyataan bahwa itu tidak (dan tidak pernah bisa) bekerja dan jelas tidak pernah diuji:
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
Mari kita perbaiki kesalahan sintaks dan ps
argumen yang rusak dan dapatkan:
running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
echo Already locked
exit 6
fi
Script ini akan selalu keluar 6, setiap kali, tidak peduli bagaimana Anda menjalankannya.
Jika Anda menjalankannya ./myscript
, maka ps
hasilnya hanya akan 12345 -bash
, yang tidak cocok dengan string yang diperlukan 12345 bash ./myscript
, sehingga akan gagal.
Jika Anda menjalankannya bash myscript
, segalanya menjadi lebih menarik. Proses bash bercabang untuk menjalankan pipa, dan shell anak menjalankan ps
dan grep
. Shell asli dan shell anak akan muncul di ps
output, kira-kira seperti ini:
25793 bash myscript
25795 bash myscript
Itu bukan hasil yang diharapkan $$ bash $0
, jadi skrip Anda akan keluar.
Pendekatan yang rusak # 2
Sekarang dalam keadilan bagi pengguna yang menulis pendekatan # 1 yang rusak, saya melakukan sesuatu yang serupa saat pertama kali mencoba ini:
if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
echo >&2 "There are other copies of the script running; exiting."
ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
exit 1
fi
Ini hampir berhasil. Tetapi fakta forking untuk menjalankan pipa membuang ini. Jadi yang ini akan selalu keluar juga.
Pendekatan tidak dapat diandalkan # 3
pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
echo >&2 "There are other copies of this script running; exiting."
ps -fq "${not_this_process//$'\n'/ }"
exit 1
fi
Versi ini menghindari masalah forking pipa dalam pendekatan # 2 dengan terlebih dahulu mendapatkan semua PID yang memiliki skrip saat ini dalam argumen baris perintah mereka, dan kemudian memfilter pidlist itu, secara terpisah, untuk menghilangkan PID dari skrip saat ini.
Ini mungkin berhasil ... asalkan tidak ada proses lain yang memiliki baris perintah yang cocok dengan $0
, dan menyediakan skrip selalu disebut dengan cara yang sama (misalnya jika itu disebut dengan jalur relatif dan kemudian jalur absolut, contoh terakhir tidak akan melihat yang sebelumnya ).
Pendekatan tidak dapat diandalkan # 4
Jadi bagaimana jika kita lewati memeriksa baris perintah penuh, karena itu mungkin tidak menunjukkan skrip benar-benar berjalan, dan lsof
bukannya memeriksa untuk menemukan semua proses yang memiliki skrip ini terbuka?
Ya, pendekatan ini sebenarnya tidak terlalu buruk:
if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running. Exiting to avoid conflicts."
ps >&2 -fq "${otherpids//$'\n'/ }"
exit 1
fi
Tentu saja, jika salinan skrip sedang berjalan, maka instance baru akan mulai baik-baik saja dan Anda akan menjalankan dua salinan .
Atau jika skrip yang berjalan dimodifikasi (mis. Dengan Vim atau dengan a git checkout
), maka skrip versi "baru" akan mulai tanpa masalah, karena keduanya Vim dan git checkout
menghasilkan file baru (inode baru) menggantikan yang lama.
Namun, jika skrip tidak pernah dimodifikasi dan tidak pernah disalin, maka versi ini cukup bagus. Tidak ada kondisi balapan karena file skrip harus dibuka sebelum pemeriksaan dapat dicapai.
Masih bisa ada false positive jika proses lain membuka file skrip, tetapi perhatikan bahwa meskipun itu terbuka untuk diedit di Vim, vim tidak benar-benar menahan file skrip terbuka sehingga tidak akan menghasilkan false positive.
Tapi ingat, jangan gunakan pendekatan ini jika skrip mungkin diedit atau disalin karena Anda akan mendapatkan negatif palsu, yaitu beberapa kejadian berjalan sekaligus - jadi fakta bahwa mengedit dengan Vim tidak memberikan hasil positif palsu, seharusnya tidak menjadi masalah. kepadamu. Saya menyebutkannya, karena pendekatan # 3 memang memberikan positif palsu (yaitu menolak untuk memulai) jika Anda memiliki skrip terbuka dengan Vim.
Lalu apa yang harus dilakukan?
Jawaban teratas untuk pertanyaan ini memberikan pendekatan yang bagus dan solid.
Mungkin Anda bisa menulis yang lebih baik ... tetapi jika Anda tidak memahami semua masalah dan peringatan dengan semua pendekatan di atas, Anda tidak akan menulis metode penguncian yang menghindari semuanya.
kill
ed; dan tampaknya merupakan praktik yang baik untuk menyimpan pid Anda sendiri di lockfile, daripada hanya menyentuhnya.