অতিরিক্ত সরঞ্জামগুলির প্রয়োজন হয় না এমন একটি সমাধান অগ্রাধিকার দেওয়া হবে।
ln -s my.pid .lock
কোনও কিছু লকটি দাবি করবে (তারপরে echo $$ > my.pid
) এবং ব্যর্থতার কারণে এটি সংরক্ষিত পিআইডি .lock
সত্যিই স্ক্রিপ্টের একটি সক্রিয় উদাহরণ কিনা
অতিরিক্ত সরঞ্জামগুলির প্রয়োজন হয় না এমন একটি সমাধান অগ্রাধিকার দেওয়া হবে।
ln -s my.pid .lock
কোনও কিছু লকটি দাবি করবে (তারপরে echo $$ > my.pid
) এবং ব্যর্থতার কারণে এটি সংরক্ষিত পিআইডি .lock
সত্যিই স্ক্রিপ্টের একটি সক্রিয় উদাহরণ কিনা
উত্তর:
প্রায় এনএসজি-র উত্তরের মতো: একটি লক ডিরেক্টরি ব্যবহার করুন । ডিরেক্টরি নির্মাণ লিনাক্স এবং ইউনিক্স এবং * বিএসডি এবং অন্যান্য অনেকগুলি ওএসের আওতায় পারমাণবিক।
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
আপনি ডিবাগিংয়ের উদ্দেশ্যে লক ডিরেক্টরিতে একটি ফাইলের মধ্যে লকিং শের পিআইডি রাখতে পারেন, তবে ভাবনার ফাঁদে পড়বেন না যে লকিংয়ের প্রক্রিয়াটি এখনও কার্যকর হয় কিনা তা দেখতে আপনি সেই পিআইডি চেক করতে পারেন। প্রচুর বর্ণের পরিস্থিতি সেই পথে পড়ে lie
mkdir
এনএফএস-এ পারমাণবিক নয় এমন দাবি দাবি করা হয়েছে (যা আমার পক্ষে হয় না তবে আমার ধারণা অনুমান করা উচিত যে এটি যদি সত্য হয়)
/tmp
এনএফএস ভাগ করে নেওয়া হয় না, তাই এটি ঠিক হওয়া উচিত।
rm -rf
লক ডিরেক্টরিটি সরানোর জন্য ব্যবহার করব । rmdir
যদি কেউ (অগত্যা আপনি না) ডিরেক্টরিতে একটি ফাইল যুক্ত করতে সক্ষম হন তবে ব্যর্থ হবে।
ব্রুস এডিগার এর উত্তর যুক্ত করতে এবং এই উত্তর থেকে অনুপ্রাণিত হয়ে স্ক্রিপ্ট সমাপ্তির বিরুদ্ধে রক্ষা করতে আপনার পরিষ্কার-পরিচ্ছন্নতায় আরও স্মার্ট যুক্ত করতে হবে:
#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
lsof $0
খারাপ হয় না?
$$
লক ফাইলটিতে লিখে রেসের অবস্থা হ্রাস করতে পারেন । তারপরে sleep
একটি স্বল্প বিরতির জন্য এবং এটি আবার পড়ুন। যদি পিআইডি এখনও আপনার হয়, আপনি সফলভাবে লকটি অর্জন করেছেন। একেবারে কোনও অতিরিক্ত সরঞ্জামের প্রয়োজন।
আপনি যদি নিশ্চিত করতে চান যে আপনার স্ক্রিপ্টের কেবলমাত্র একটি উদাহরণ চলছে তবে একবার দেখুন:
আপনার স্ক্রিপ্ট লক করুন (সমান্তরাল রান বিরুদ্ধে)
অন্যথায় আপনি চেক 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>
একসাথে বেশ কয়েকটি উদাহরণ কাঁটাচামচ করে-চালিয়ে যান ।
[[(lsof $0 | wc -l) > 2]] && exit
আসলে আসলে যথেষ্ট, বা এটিও রেসের শর্তে প্রবণ?
বাশ স্ক্রিপ্টের একক উদাহরণ চলে তা নিশ্চিত করার জন্য অন্য একটি উপায়:
#!/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
ইতিমধ্যে চলমান থাকলে বিদ্যমান স্ক্রিপ্টের পিআইডি পেয়ে যায় বা অন্য কোনও স্ক্রিপ্ট না চললে ত্রুটি কোড 1 সহ প্রস্থান করে
যদিও আপনি অতিরিক্ত সরঞ্জাম ছাড়াই সমাধান চেয়েছিলেন, এটি আমার প্রিয় উপায় flock
:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
এটি এর উদাহরণ বিভাগ থেকে আসে man flock
, যা আরও ব্যাখ্যা করে:
এটি শেল স্ক্রিপ্টগুলির জন্য দরকারী বয়লারপ্লেট কোড। আপনি যে শেল স্ক্রিপ্টটি লক করতে চান তার শীর্ষে রাখুন এবং এটি স্বয়ংক্রিয়ভাবে প্রথম দৌলে নিজেকে লক হয়ে যাবে। যদি env var $ FLOCKER চালিত শেল স্ক্রিপ্টে সেট না করা থাকে তবে সঠিকভাবে যুক্তি দিয়ে নিজেকে পুনরায় চালিত করার আগে ঝাঁকটি নির্বাহ করুন এবং একচেটিয়া অ-ব্লকিং লক (স্ক্রিপ্টটিকে লক ফাইল হিসাবে ব্যবহার করুন) ধরুন। এটি FLOCKER env varকে সঠিক মান হিসাবে সেট করে যাতে এটি আবার চালিত হয় না।
বিবেচনা করার বিষয়গুলি:
flock
, উদাহরণস্বরূপ স্ক্রিপ্টটি একটি ত্রুটিযুক্ত সাথে এটি শেষ না হলে এটি শেষ করেএটি আনসেলমোর উত্তরের একটি পরিবর্তিত সংস্করণ । ধারণাটি হ'ল বাশ স্ক্রিপ্টটি নিজেই একটি পঠনযোগ্য ফাইল বর্ণনাকারী তৈরি করা এবং 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 ব্যবহার করছি , এমনকি আমি ফাইলের নাম এবং ফাইলের পথও পরিবর্তন করি ।
আমি ট্র্যাপ ও লক ফাইলটি ব্যবহার করছি না, কারণ আমার সার্ভারটি হঠাৎ ডাউন হয়ে গেলে সার্ভার উপরে উঠে যাওয়ার পরে আমাকে ম্যানুয়ালি লক ফাইলটি সরিয়ে ফেলতে হবে।
দ্রষ্টব্য: #! / বিন / বাশ প্রথম লাইনে গ্রেপ পিএসের জন্য প্রয়োজনীয়
#!/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
mysum
এবং fsum
যখন আপনি আর কোনও চেকসামের কথা বলছেন না।
আপনি এটি ব্যবহার করতে পারেন: 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
আপনি সমস্ত মূল স্ক্রিপ্ট রাখতে পারেন।