একবারে শেল স্ক্রিপ্টের কেবলমাত্র একটি উদাহরণ চলছে তা নিশ্চিত করার জন্য দ্রুত এবং নোংরা উপায়


179

শেল স্ক্রিপ্টের একটিমাত্র নির্দিষ্ট সময় নির্দিষ্ট সময়ে চলছে কিনা তা নিশ্চিত করার দ্রুত এবং নোংরা উপায় কী?


সম্পর্কিত @ Unix.SE: unix.stackexchange.com/questions/22044/...
Palec

উত্তর:


109

এখানে এমন একটি বাস্তবায়ন রয়েছে যা একটি লকফিল ব্যবহার করে এবং এতে একটি পিআইডি প্রতিধ্বনি করে। পিডফিল অপসারণের আগে প্রক্রিয়াটি মারা গেলে এটি সুরক্ষা হিসাবে কাজ করে :

LOCKFILE=/tmp/lock.txt
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
    echo "already running"
    exit
fi

# make sure the lockfile is removed when we exit and then claim it
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
echo $$ > ${LOCKFILE}

# do stuff
sleep 1000

rm -f ${LOCKFILE}

এখানে কৌতুকটি হ'ল kill -0যা কোনও সিগন্যাল সরবরাহ করে না তবে প্রদত্ত পিআইডি সহ কোনও প্রক্রিয়া বিদ্যমান কিনা তা পরীক্ষা করে দেখুন। এছাড়াও কলটি trapনিশ্চিত করবে যে আপনার প্রক্রিয়াটি মারা গেলেও (ব্যতীত ) লকফিলটি সরানো হয়েছে kill -9


73
ইতিমধ্যে anther জবাব সম্পর্কে একটি মন্তব্যে আগেই উল্লেখ করা হয়েছে, এর মধ্যে মারাত্মক ত্রুটি রয়েছে - অন্য স্ক্রিপ্টটি যদি চেক এবং প্রতিধ্বনির মধ্যে শুরু হয়, তবে আপনি টোস্ট হয়ে আছেন।
পল টমবলিন 0

1
সিমলিংকের কৌশলটি খুব ঝরঝরে, তবে যদি লকফাইলের মালিক -9'd মারছে বা সিস্টেমটি ক্র্যাশ হয়ে গেছে, তখনও সিমলিংকটি পড়ার জন্য রেস শর্ত রয়েছে, মালিক চলে গেছে তা লক্ষ্য করুন এবং তারপরে এটি মুছুন। আমি আমার সমাধান সঙ্গে স্টিকিং করছি।
bmdhacks

9
পার্ক (1) বা লকফিল (1) ব্যবহার করে শেলটিতে পারমাণবিক চেক এবং ক্রিয়েট পাওয়া যায়। অন্যান্য উত্তর দেখুন।
ডিএমকেকে --- প্রাক্তন-মডারেটর বিড়ালছানা

3
পারমাণবিক চেক করার পোর্টেবল উপায়ে আমার উত্তর দেখুন এবং ঝাঁক বা লকফাইলের মতো ইউটিলিটির উপর নির্ভর না করে তৈরি করুন।
lhunath

2
এটি পারমাণবিক নয় এবং এভাবে অকেজো। পরীক্ষা ও সেট করার জন্য আপনার একটি পারমাণবিক প্রক্রিয়া দরকার।
কে রিচার্ড

214

flock(1)একটি ফাইল স্ক্রিপ্ট লক একটি ফাইল বর্ণনাকারী করতে ব্যবহার করুন । এইভাবে আপনি এমনকি স্ক্রিপ্টের বিভিন্ন অংশ সিঙ্ক্রোনাইজ করতে পারেন।

#!/bin/bash

(
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200 || exit 1

  # Do stuff

) 200>/var/lock/.myscript.exclusivelock

এটি সেই কোডটি নিশ্চিত করে (এবং )একসাথে কেবল একটি প্রক্রিয়া দ্বারা চালিত হয় এবং প্রক্রিয়াটি কোনও লকের জন্য খুব বেশি সময় অপেক্ষা করে না।

কেভেট: এই বিশেষ আদেশটি একটি অংশ util-linux। আপনি যদি লিনাক্স ব্যতীত অপারেটিং সিস্টেম চালনা করেন তবে এটি উপলভ্য বা নাও থাকতে পারে।


11
200 কি? এটি মনুলের "এফডি" বলে, তবে এর অর্থ কী তা আমি জানি না।
chovy

4
@ শেভি "ফাইল বর্ণনাকারী", একটি পূর্ণাঙ্গ হ্যান্ডেল একটি খোলার ফাইল নির্ধারণ করে।
অ্যালেক্স বি

6
যদি অন্য কেউ ভাবছেন: সিনট্যাক্সটির ( command A ) command Bজন্য একটি সাবশেল আহ্বান জানানো হয়েছে command ATldp.org/LDP/abs/html/subshells.htmlনথিভুক্ত
সাব-শেল

1
আমি মনে করি সাব-শেলের অভ্যন্তরের কোডটি আরও বেশি হওয়া উচিত: if flock -x -w 10 200; then ...Do stuff...; else echo "Failed to lock file" 1>&2; fiযাতে সময়সীমাটি ঘটে (অন্য কোনও প্রক্রিয়াতে ফাইলটি লক হয়ে আছে), এই স্ক্রিপ্টটি এগিয়ে যায় না এবং ফাইলটি সংশোধন করে না। সম্ভবত ... পাল্টা যুক্তিটি 'তবে এটি যদি 10 সেকেন্ড সময় নেয় এবং লকটি এখনও পাওয়া না যায় তবে এটি কখনই উপলভ্য হবে না' সম্ভবতঃ কারণ লকটি ধরে রাখার প্রক্রিয়াটি শেষ হচ্ছে না (সম্ভবত এটি চালিত হচ্ছে) একটি ডিবাগার অধীনে?)।
জোনাথন লেফলার

1
পুনঃনির্দেশিত ফাইলটি লকটির জন্য কাজ করার জন্য কেবলমাত্র একটি প্লেসফোল্ডার, এতে কোনও অর্থবহ ডেটা .ুকে যায় না। এর exitভিতরে থেকে অংশটি ( )। সাবপ্রসেসটি শেষ হয়ে গেলে, লকটি স্বয়ংক্রিয়ভাবে মুক্তি পায়, কারণ এটি ধারণ করার কোনও প্রক্রিয়া নেই।
ক্লেক

158

"লক ফাইল" এর অস্তিত্ব পরীক্ষা করে এমন সমস্ত পদ্ধতির ত্রুটি রয়েছে।

কেন? কারণ কোনও ফাইল উপস্থিত রয়েছে কিনা তা যাচাই করে দেখার জন্য এবং একক পারমাণবিক ক্রিয়ায় এটি তৈরি করার কোনও উপায় নেই। এর জন্য; সেখানে একটি জাতি এই শর্তে যে হয় হবে পারস্পরিক বর্জনের বিরতি আপনার প্রচেষ্টা করা।

পরিবর্তে, আপনি ব্যবহার করা প্রয়োজন mkdirmkdirএটি এখনও উপস্থিত না থাকলে একটি ডিরেক্টরি তৈরি করে এবং যদি এটি হয় তবে এটি একটি প্রস্থান কোড নির্ধারণ করে। আরও গুরুত্বপূর্ণ বিষয়, এটি এই একক পারমাণবিক ক্রিয়ায় এটি করে যা এই দৃশ্যের জন্য নিখুঁত করে তোলে।

if ! mkdir /tmp/myscript.lock 2>/dev/null; then
    echo "Myscript is already running." >&2
    exit 1
fi

সমস্ত বিবরণের জন্য, দুর্দান্ত বাশফাক দেখুন: http://mywiki.wooledge.org/BashFAQ/045

আপনি যদি বাসি তালার যত্ন নিতে চান তবে ফুসার (1) ব্যবহারের সুযোগ আসে। এখানে কেবলমাত্র প্রতিকূলতাটি হ'ল অপারেশনটি প্রায় এক সেকেন্ড সময় নেয় তাই এটি তাত্ক্ষণিকভাবে নয়।

এখানে আমি একটি ফাংশন লিখেছি যা একবার ফুয়েজার ব্যবহার করে সমস্যার সমাধান করে:

#       mutex file
#
# Open a mutual exclusion lock on the file, unless another process already owns one.
#
# If the file is already locked by another process, the operation fails.
# This function defines a lock on a file as having a file descriptor open to the file.
# This function uses FD 9 to open a lock on the file.  To release the lock, close FD 9:
# exec 9>&-
#
mutex() {
    local file=$1 pid pids 

    exec 9>>"$file"
    { pids=$(fuser -f "$file"); } 2>&- 9>&- 
    for pid in $pids; do
        [[ $pid = $$ ]] && continue

        exec 9>&- 
        return 1 # Locked by a pid.
    done 
}

আপনি এটির মতো স্ক্রিপ্টে এটি ব্যবহার করতে পারেন:

mutex /var/run/myscript.lock || { echo "Already running." >&2; exit 1; }

আপনি যদি বহনযোগ্যতার বিষয়ে চিন্তা না করেন (এই সমাধানগুলি কোনও ইউনিক্স বাক্সে কার্যকরভাবে কাজ করা উচিত), লিনাক্সের ফিউজার (1) কিছু অতিরিক্ত বিকল্প সরবরাহ করে এবং সেখানে ঝাঁক (1) রয়েছে


1
if ! mkdirলকডিরের ভিতরে থাকা পিআইডি (সসেসফুল স্টার্টআপে) প্রক্রিয়াটি আসলে চলমান এবং স্ট্যালিন সুরক্ষার জন্য স্ক্রিপ্টের অনুরূপ কিনা তা পরীক্ষা করে আপনি অংশটি একত্রিত করতে পারেন । এটি পুনরায় বুটের পরে পিআইডি পুনরায় ব্যবহার করা থেকে রক্ষা করবে এবং এমনকি প্রয়োজন নেই fuser
টোবিয়াস কেইনজলার

4
এটি অবশ্যই সত্য যে mkdirএটি পারমাণবিক ক্রিয়াকলাপ হিসাবে সংজ্ঞায়িত হয়নি এবং যেমন "পার্শ্ব-প্রতিক্রিয়া" ফাইল সিস্টেমের একটি বাস্তবায়ন বিশদ। আমি তাকে পুরোপুরি বিশ্বাস করি যদি তিনি বলেন যে এনএফএস এটি পারমাণবিক পদ্ধতিতে প্রয়োগ করে না। যদিও আমি সন্দেহ করি না যে এটি আপনার /tmpকোনও এনএফএস শেয়ার হবে এবং সম্ভবত এটি কোনও এফএস দ্বারা সরবরাহ করা হবে যা mkdirপরমাণুভাবে প্রয়োগ করে ।
lhunath

5
তবে একটি নিয়মিত ফাইলের অস্তিত্বের জন্য যাচাই করার উপায় রয়েছে এবং এটি যদি না হয় তবে এটি এটমিকভাবে lnতৈরি করার জন্য : অন্য ফাইল থেকে একটি হার্ড লিঙ্ক তৈরি করতে ব্যবহার করে । আপনার যদি অদ্ভুত ফাইল সিস্টেম থাকে যা এর গ্যারান্টি দেয় না তবে আপনি নতুন ফাইলের ইনোডটি পরে পরীক্ষা করতে পারেন এটি আসল ফাইলের মতো কিনা।
জুয়ান সিপ্পিডেস

4
সেখানে হয় এটা - 'একটি ফাইল বিদ্যমান কিনা চেক করুন এবং একটি একক পারমাণবিক এটা কর্ম তৈরি করতে একটি পথ' open(... O_CREAT|O_EXCL)। এটি করার জন্য আপনার কেবল একটি উপযুক্ত ব্যবহারকারী প্রোগ্রাম প্রয়োজন, যেমন lockfile-create(ইন lockfile-progs) বা dotlockfile(ইন liblockfile-bin)। এবং নিশ্চিত হয়ে নিন যে আপনি সঠিকভাবে পরিষ্কার করেছেন (উদাঃ trap EXIT), বা বাসি লকগুলির পরীক্ষা করুন (উদাহরণস্বরূপ --use-pid)।
টবি স্পিড

5
"" লক ফাইলগুলির "অস্তিত্বের পরীক্ষা করে এমন সমস্ত পদ্ধতির ত্রুটি রয়েছে Why কেন? কারণ কোনও ফাইল উপস্থিত রয়েছে কিনা তা যাচাই করে দেখার জন্য এবং কোনও একক পারমাণবিক ক্রিয়ায় এটি তৈরি করার কোনও উপায় নেই" "- এটি পারমাণবিক করতে এটি এখানে করতে হবে কার্নেল স্তর - এবং এটি কার্নেল স্তরে ফ্লক (1) linux.die.net/man/1/flock দিয়ে করা হয় যা ম্যান কপিরাইটের তারিখ থেকে কমপক্ষে ২০০ 2006 সাল থেকে দেখা যায়। সুতরাং আমি একটি ডাউনওয়েট তৈরি করেছি - - 1), ব্যক্তিগত কিছুই নয়, কেবল দৃ strong় বিশ্বাস আছে যে কার্নেল বিকাশকারীদের দ্বারা সরবরাহিত কর্নেল বাস্তবায়িত সরঞ্জামগুলি ব্যবহার করা সঠিক।
ক্রেগ হিক্স

42

ঝাঁক (২) সিস্টেম কলের চারপাশে একটি মোড়কের কল রয়েছে, কল্পনাতীতভাবে, ঝাঁক (1)। এটি ক্লিনআপ ইত্যাদির চিন্তা না করেই নির্ভরযোগ্যভাবে একচেটিয়া লকগুলি অর্জন করা তুলনামূলকভাবে সহজ করে তোলে শেল স্ক্রিপ্টে এটি কীভাবে ব্যবহার করা যায় সে সম্পর্কে ম্যান পৃষ্ঠায় উদাহরণ রয়েছে ।


3
flock()সিস্টেম কল POSIX নয় এবং NFS মাউন্ট উপর ফাইলের জন্য কাজ করে না।
maxschlepzig

17
ক্রোন জব থেকে চালানো আমি flock -x -n %lock file% -c "%command%"নিশ্চিত হয়েছি যে কেবলমাত্র একটি উদাহরণ কার্যকর হচ্ছে।
রাইল

ওহ, অকল্পনীয় পালের পরিবর্তে (1) তাদের পশুপালের (ইউ) মতো কিছু করা উচিত ছিল। ..। এটির কিছুটা পরিচিতি আছে। । .মুগ্ধ মনে হয়েছে আমি শুনেছি এক বা দু'বার আগে।
কেন্ট ক্রুসেকবার্গ

এটি উল্লেখযোগ্য যে ফ্লক (2) ডকুমেন্টেশনগুলি কেবল ফাইলগুলির সাথে ব্যবহার নির্দিষ্ট করে তবে ফ্লক (1) ডকুমেন্টেশন ফাইল বা ডিরেক্টরি যে কোনও একটির সাথে ব্যবহার নির্দিষ্ট করে। ফ্লকের (1) ডকুমেন্টেশনটি কীভাবে সৃষ্টির সময় পার্থক্যটি নির্দেশ করতে পারে সে সম্পর্কে স্পষ্ট নয় তবে আমি ধরে নিয়েছি এটি একটি চূড়ান্ত "/" যুক্ত করে সম্পন্ন হয়েছে। যাইহোক, যদি ফ্লক (1) ডিরেক্টরি পরিচালনা করতে পারে তবে পশুপাল (2) না পারে, তবে ঝাঁক (1) শুধুমাত্র পালের (2) উপর প্রয়োগ করা হয় না।
ক্রেগ হিক্স

27

আপনার পালের মতো পারমাণবিক অপারেশন প্রয়োজন, অন্যথায় এটি ব্যর্থ হবে।

তবে পশুপাল না পাওয়া গেলে করণীয়। ঠিক আছে এমকিডির। এটিও পারমাণবিক অপারেশন। কেবলমাত্র একটি প্রক্রিয়া সফল এমকেডিরের ফলশ্রুতিতে আসবে, অন্য সমস্ত ব্যর্থ হবে।

সুতরাং কোডটি হ'ল:

if mkdir /var/lock/.myscript.exclusivelock
then
  # do stuff
  :
  rmdir /var/lock/.myscript.exclusivelock
fi

আপনার স্ক্রিপ্ট আর কখনও চালিত হবে না এমন দুর্ঘটনার পরে আপনাকে বাসি লকগুলির যত্ন নেওয়া দরকার।


1
এটি কয়েকবার একসাথে চালান (যেমন "./a.sh & ./a.sh & ./a.sh & ./a.sh & ./a.sh & ./a.sh& ./a.sh & ") এবং স্ক্রিপ্ট কয়েকবারের মধ্যে ফাঁস হবে।
নিপ্পাইসরাস

7
@ নিপ্পিসৌরাস: এই লক করার পদ্ধতিটি ফুটো হয় না। আপনি যা দেখেছিলেন তা হ'ল সমস্ত অনুলিপিগুলি শুরুর আগে প্রাথমিক স্ক্রিপ্টটি সমাপ্ত হয়েছিল, সুতরাং অন্য একটি লকটি পেতে (সঠিকভাবে) সক্ষম হয়েছিল। এই মিথ্যা ধনাত্মকতা এড়াতে, sleep 10আগে যুক্ত করুন rmdirএবং আবার ক্যাসকেড করার চেষ্টা করুন - কিছুই "ফুটো" হবে না।
স্যার অ্যাথোস

অন্যান্য উত্স দাবি করেছে যে এনকেএস-এর মতো কিছু ফাইল সিস্টেমে এমকেডির পারমাণবিক নয়। এবং বিটিডব্লিউ আমি এমন অনুষ্ঠানগুলি দেখেছি যেখানে এনএফএসের একযোগে পুনরাবৃত্ত এমকেডির জেনকিনস ম্যাট্রিক্স চাকরির সাথে মাঝে মাঝে ত্রুটির দিকে পরিচালিত করে। সুতরাং আমি বেশ নিশ্চিত যে এটি ক্ষেত্রে। তবে এমকেডির কম দাবী ব্যবহারের ক্ষেত্রে আইএমওর জন্য বেশ সুন্দর।
akostadinov

আপনি নিয়মিত ফাইলগুলির সাথে বাশ'স নোক্লোবার বিকল্পটি ব্যবহার করতে পারেন।
প্লেকে

26

লকিংকে নির্ভরযোগ্য করে তুলতে আপনার একটি পারমাণবিক অপারেশন প্রয়োজন। উপরোক্ত প্রস্তাবগুলির মধ্যে অনেকগুলি পারমাণবিক নয়। প্রস্তাবিত লকফিল (1) ইউটিলিটিটি ম্যান-পৃষ্ঠাতে উল্লিখিত হিসাবে এটির "এনএফএস-প্রতিরোধী" হিসাবে আশাব্যঞ্জক বলে মনে হচ্ছে। যদি আপনার ওএস লকফিল (1) সমর্থন করে না এবং আপনার সমাধানটি এনএফএসে কাজ করতে হয় তবে আপনার কাছে খুব বেশি বিকল্প নেই ...

এনএফএসভি 2 এর দুটি পরমাণু অপারেশন রয়েছে:

  • সিমবলিক লিঙ্ক
  • পুনঃনামকরণ

এনএফএসভি 3 এর সাথে তৈরি কলটিও পারমাণবিক।

ডিরেক্টরি ক্রিয়াকলাপগুলি এনএফএসভি 2 এবং এনএফএসভি 3 এর অধীনে পারমাণবিক নয় (অনুগ্রহ করে ব্রেন্ট ক্যালাহান, আইএসবিএন 0-201-32570-5-র লেখা 'এনএফএস ইলাস্ট্রেটেড' বইটি পড়ুন; ব্রেন্ট সান-এ এনএফএস-অভিজ্ঞ))

এটি জানার পরে, আপনি ফাইল এবং ডিরেক্টরিগুলির জন্য স্পিন-লকগুলি প্রয়োগ করতে পারেন (শ্যালে, পিএইচপি নয়):

লক বর্তমান দির:

while ! ln -s . lock; do :; done

একটি ফাইল লক করুন:

while ! ln -s ${f} ${f}.lock; do :; done

আনলক বর্তমান দির (অনুমান, চলমান প্রক্রিয়াটি সত্যিই লকটি অর্জন করেছে):

mv lock deleteme && rm deleteme

একটি ফাইল আনলক করুন (ধারণা, চলমান প্রক্রিয়াটি সত্যিই লকটি অর্জন করেছে):

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme

অপসারণটিও পারমাণবিক নয়, অতএব প্রথমে পুনরায় নামকরণ (যা পরমাণু) এবং তারপরে অপসারণ।

সিমলিংক এবং পুনঃনামকরণ কলগুলির জন্য, উভয় ফাইলের নাম একই ফাইল সিস্টেমে থাকতে হবে। আমার প্রস্তাব: কেবলমাত্র সরল ফাইলের নাম ব্যবহার করুন (কোনও পাথ নেই) এবং একই ডিরেক্টরিতে ফাইল এবং লক রাখুন।


এনএফএস ইলাস্ট্রেটেডের কোন পৃষ্ঠাগুলি এমকিডির এনএফএসের চেয়ে বেশি পারমাণবিক নয়?
maxschlepzig

এই কৌশলটির জন্য ধন্যবাদ। আমার নতুন শেল লাইবটিতে একটি শেল মিটেক্স বাস্তবায়ন পাওয়া যায়: github.com/Offirmo/offirmo-shell-lib , " মিটেক্স " দেখুন। এটি lockfileউপলব্ধ হলে এটি ব্যবহার করে , বা symlinkনা হলে এই পদ্ধতিতে ফ্যালব্যাক ।
অফির্মো

খুশী হলাম। দুর্ভাগ্যক্রমে এই পদ্ধতিটি বাসি লকগুলি স্বয়ংক্রিয়ভাবে মোছার কোনও উপায় সরবরাহ করে না।
রিচার্ড হ্যানসেন

দুটি স্তরের আনলক ( mv, rm) এর জন্য, দুটি প্রক্রিয়া পি 1, পি 2 রেসিংয়ের rm -fপরিবর্তে ব্যবহার করা উচিত rm? উদাহরণস্বরূপ, পি 1 আনলকটি শুরু করে mv, তারপরে পি 2 লকগুলি, তারপরে পি 2 আনলক করে (উভয় mvএবং উভয় rm), শেষ পর্যন্ত পি 1 প্রচেষ্টা rmএবং ব্যর্থ হয়।
ম্যাট ওয়ালিস

1
@MattWallis গত সমস্যা সহজে অন্তর্ভুক্ত করে নির্বাপিত হতে পারে যে $$${f}.deletemeফাইলের নাম।
স্টিফান মাজেউস্কি

23

আরেকটি বিকল্প হ'ল চালিয়ে শেলের noclobberবিকল্পটি ব্যবহার করা set -C। তারপর >ব্যর্থ হয়ে যাবে ফাইল ইতিমধ্যেই বিদ্যমান।

সংক্ষেপে:

set -C
lockfile="/tmp/locktest.lock"
if echo "$$" > "$lockfile"; then
    echo "Successfully acquired lock"
    # do work
    rm "$lockfile"    # XXX or via trap - see below
else
    echo "Cannot acquire lock - already locked by $(cat "$lockfile")"
fi

এটি শেলটি কল করার কারণ দেয়:

open(pathname, O_CREAT|O_EXCL)

যা পরমাণুভাবে ফাইল তৈরি করে বা ফাইলটি ইতিমধ্যে উপস্থিত থাকলে ব্যর্থ হয়।


বাশাএফএউ 045-এর একটি মন্তব্য অনুসারে , এটি ব্যর্থ হতে পারে ksh88তবে এটি আমার সমস্ত শেলগুলিতে কাজ করে:

$ strace -e trace=creat,open -f /bin/bash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/zsh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/pdksh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/dash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3

আকর্ষণীয় যা পতাকা pdkshযুক্ত করে O_TRUNC, তবে স্পষ্টতই এটি
অনর্থক : হয় আপনি খালি ফাইল তৈরি করছেন, বা আপনি কিছু করছেন না।


আপনি কীভাবে করবেন তা rmনির্ভর করে আপনি কীভাবে অপরিষ্কার প্রস্থানগুলি পরিচালনা করতে চান তার উপর।

পরিষ্কার প্রস্থান থেকে মুছুন

অশুচি প্রস্থানটি মীমাংসিত হওয়ার কারণে এবং লকফিলটি ম্যানুয়ালি সরানো না হওয়া পর্যন্ত নতুন রান ব্যর্থ হয়।

# acquire lock
# do work (code here may call exit, etc.)
rm "$lockfile"

যে কোনও প্রস্থান থেকে মুছুন

স্ক্রিপ্ট ইতিমধ্যে চালু না থাকলে নতুন রান সফল হয়।

trap 'rm "$lockfile"' EXIT

খুব অভিনব পদ্ধতির ... এটি লক ডিরেক্টরিটি না করে লক ফাইল ব্যবহার করে পারমাণবিকতা অর্জনের এক উপায় বলে মনে হয়।
ম্যাট কলডওয়েল

চমৎকার পন্থা। :-) এক্সিট ট্র্যাপে, এটি কোনও প্রক্রিয়াটি লক ফাইলটি পরিষ্কার করতে পারে তা সীমাবদ্ধ করা উচিত। উদাহরণস্বরূপ: ফাঁদ 'যদি [[$ (বিড়াল "$ লকফিল") == "$$"]]; তারপরে আরএম "$ লকফিল"; ফাই 'প্রস্থান করুন
কেভিন সিফার্ট

1
লক ফাইলগুলি এনএফএসের চেয়ে বেশি পারমাণবিক নয়। যে কারণে লোকেরা লক ডিরেক্টরি ব্যবহার করতে চলেছে।
কে রিচার্ড

20

আপনি GNU Parallelএটির জন্য যখন এটি ডায়ালিউড হিসাবে মিটেক্স হিসাবে কাজ করে তা ব্যবহার করতে পারেন sem। সুতরাং, কংক্রিট পদগুলিতে, আপনি ব্যবহার করতে পারেন:

sem --id SCRIPTSINGLETON yourScript

যদি আপনিও একটি সময়সীমা চান, ব্যবহার করুন:

sem --id SCRIPTSINGLETON --semaphoretimeout -10 yourScript

<0 এর টাইমআউটটির অর্থ সময়সীমার মধ্যে যদি semaphore প্রকাশ না করা হয় তবে স্ক্রিপ্টটি চালানো ছাড়াই প্রস্থান করা হবে,> 0 এর টাইমআউটটি যাইহোক স্ক্রিপ্টটি চালান।

মনে রাখবেন যে এটির একটি নাম দেওয়া উচিত (সহ --id) অন্যথায় এটি নিয়ন্ত্রণকারী টার্মিনালটিতে ডিফল্ট হয়।

GNU Parallel বেশিরভাগ লিনাক্স / ওএসএক্স / ইউনিক্স প্ল্যাটফর্মগুলিতে একটি খুব সহজ ইনস্টল - এটি কেবল পার্ল স্ক্রিপ্ট।


খুব খারাপ লোকগুলি বেহুদা জবাবগুলি হ্রাস করতে নারাজ: এর ফলে নতুন প্রাসঙ্গিক উত্তরগুলি জাঙ্কের গাদাতে দাফন করা হবে।
দিমিত্রি গ্রিগরিয়েভ

4
আমাদের কেবলমাত্র প্রচুর পরিমাণে দরকার। এই যেমন একটি পরিপাটি এবং সামান্য পরিচিত উত্তর। (যদিও পেডেন্টিক ওপি চটজলদি এবং নোংরা হতে চেয়েছিল যদিও এটি দ্রুত এবং পরিষ্কার-পরিচ্ছন্ন!) semসম্পর্কিত প্রশ্নটিতে আরও unix.stackexchange.com/a/322200/199525
আংশিক মেঘলা

16

শেল স্ক্রিপ্টগুলির জন্য, আমি mkdirওভারের সাথে যেতে চাই flockকারণ এটি লকগুলি আরও পোর্টেবল করে তোলে।

যেভাবেই হোক, ব্যবহার set -eকরা যথেষ্ট নয়। কোনও কমান্ড ব্যর্থ হলে এটি কেবল স্ক্রিপ্ট থেকে প্রস্থান করে। আপনার লকগুলি এখনও পিছনে থাকবে।

যথাযথ লক ক্লিনআপের জন্য, আপনার সত্যিকার অর্থে আপনার এই ফাঁদগুলি এই স্যুয়েডো কোডের মতো সেট করা উচিত (উত্তোলন, সরলীকৃত এবং অনির্ধারিত তবে সক্রিয়ভাবে ব্যবহৃত স্ক্রিপ্টগুলি থেকে):

#=======================================================================
# Predefined Global Variables
#=======================================================================

TMPDIR=/tmp/myapp
[[ ! -d $TMP_DIR ]] \
    && mkdir -p $TMP_DIR \
    && chmod 700 $TMPDIR

LOCK_DIR=$TMP_DIR/lock

#=======================================================================
# Functions
#=======================================================================

function mklock {
    __lockdir="$LOCK_DIR/$(date +%s.%N).$$" # Private Global. Use Epoch.Nano.PID

    # If it can create $LOCK_DIR then no other instance is running
    if $(mkdir $LOCK_DIR)
    then
        mkdir $__lockdir  # create this instance's specific lock in queue
        LOCK_EXISTS=true  # Global
    else
        echo "FATAL: Lock already exists. Another copy is running or manually lock clean up required."
        exit 1001  # Or work out some sleep_while_execution_lock elsewhere
    fi
}

function rmlock {
    [[ ! -d $__lockdir ]] \
        && echo "WARNING: Lock is missing. $__lockdir does not exist" \
        || rmdir $__lockdir
}

#-----------------------------------------------------------------------
# Private Signal Traps Functions {{{2
#
# DANGER: SIGKILL cannot be trapped. So, try not to `kill -9 PID` or 
#         there will be *NO CLEAN UP*. You'll have to manually remove 
#         any locks in place.
#-----------------------------------------------------------------------
function __sig_exit {

    # Place your clean up logic here 

    # Remove the LOCK
    [[ -n $LOCK_EXISTS ]] && rmlock
}

function __sig_int {
    echo "WARNING: SIGINT caught"    
    exit 1002
}

function __sig_quit {
    echo "SIGQUIT caught"
    exit 1003
}

function __sig_term {
    echo "WARNING: SIGTERM caught"    
    exit 1015
}

#=======================================================================
# Main
#=======================================================================

# Set TRAPs
trap __sig_exit EXIT    # SIGEXIT
trap __sig_int INT      # SIGINT
trap __sig_quit QUIT    # SIGQUIT
trap __sig_term TERM    # SIGTERM

mklock

# CODE

exit # No need for cleanup code here being in the __sig_exit trap function

এখানে কি হবে। সমস্ত ট্র্যাপগুলি একটি প্রস্থান তৈরি করবে যাতে ফাংশনটি __sig_exitসর্বদা ঘটে (সিক্কিল বাদে) যা আপনার লকগুলি পরিষ্কার করে।

দ্রষ্টব্য: আমার প্রস্থান মানগুলি কম মান নয়। কেন? বিভিন্ন ব্যাচ প্রসেসিং সিস্টেমগুলি 0 থেকে 31 এর মধ্যে সংখ্যার প্রত্যাশা তৈরি করে বা তাদের কাছে প্রত্যাশা রাখে them এগুলিকে অন্য কিছুতে সেট করে, আমার স্ক্রিপ্টগুলি এবং ব্যাচ স্ট্রিমগুলি পূর্ববর্তী ব্যাচের কাজ বা স্ক্রিপ্ট অনুসারে প্রতিক্রিয়া জানাতে পারে।


2
আপনার স্ক্রিপ্টটি খুব ভার্জোজ, আমার মনে হয় অনেক ছোট হতে পারে তবে সামগ্রিকভাবে হ্যাঁ, এটি সঠিকভাবে করার জন্য আপনাকে ফাঁদগুলি সেট আপ করতে হবে। আমি সাইনআপ যোগ করব।
মোজুবা

এটি works LOCK_DIR যাচাই করে দেখা যায় না যদিও এটি $ __ লকডিরটিকে সরিয়ে দেয় This লকটি অপসারণ করার সময় আমার পরামর্শ দেওয়া উচিত আপনি আরএম-OC লক_ডিআর করবেন?
বেভাদা

আপনার পরামর্শের জন্য ধন্যবাদ। উপরের কোডটি উত্তোলন করা হয়েছিল এবং একটি পিচুইডো কোড ফ্যাশনে স্থাপন করা হয়েছে যাতে এটি ভাবার ব্যবহারের ভিত্তিতে টিউনিংয়ের প্রয়োজন হবে। যাইহোক, আমি ইচ্ছাকৃতভাবে আমার ক্ষেত্রে rmdir এর সাথে গিয়েছিলাম কারণ rmdir নিরাপদে ডিরেক্টরিগুলি সরান কেবল_ যদি সেগুলি খালি থাকে। ভাবেন এমন PID, ফাইল, ইত্যাদি তারা আরো আক্রমনাত্মক তাদের লক পরিষ্করণ পরিবর্তন উচিত তাদের মধ্যে সম্পদ স্থাপন হয় rm -r $LOCK_DIRবা এমনকি প্রয়োজনীয় যেমন ফোর্স (যেমন আমি যেমন আপেক্ষিক আঁচড়ের দাগ ফাইল অধিষ্ঠিত যেমন বিশেষ ক্ষেত্রে খুব কাজ করেছেন)। চিয়ার্স।
মার্ক স্টিনসন

আপনি পরীক্ষা করেছেন exit 1002?
গিলস কুইনট

13

সত্যিই দ্রুত এবং সত্যিই নোংরা? আপনার স্ক্রিপ্টের শীর্ষে এই ওয়ান-লাইনারটি কাজ করবে:

[[ $(pgrep -c "`basename \"$0\"`") -gt 1 ]] && exit

অবশ্যই, নিশ্চিত করুন যে আপনার স্ক্রিপ্টের নামটি অনন্য। :)


আমি এটি পরীক্ষা করার জন্য এটি কীভাবে অনুকরণ করব? ইতিমধ্যে চালু থাকলে কোনও লাইনে দু'বার স্ক্রিপ্ট শুরু করার এবং কোনও সতর্কতা পেতে কী উপায় আছে?
রুবু 77

2
এটি মোটেই কাজ করছে না! চেক কেন -gt 2? গ্রেপ সবসময় পিএস এর ফলাফলের মধ্যে নিজেকে খুঁজে পায় না!
21

pgrepপসিক্সে নেই। আপনি যদি এটিকে বহনযোগ্যভাবে কাজ করতে চান তবে আপনার পসিক্স প্রয়োজন psএবং এর আউটপুট প্রক্রিয়া করা উচিত ।
পেরেক

ওএসএক্স -cবিদ্যমান নেই, আপনাকে ব্যবহার করতে হবে | wc -l। সংখ্যার তুলনা সম্পর্কে: -gt 1প্রথম উদাহরণটি নিজে দেখায় যেহেতু চেক করা হয়।
বেনিয়ামিন পিটার

6

এখানে একটি পদ্ধতির সাথে পারমাণবিক ডিরেক্টরি লকিংয়ের সাথে PID এর মাধ্যমে বাসি লকটির জন্য একটি চেক সংযুক্ত করা হয় এবং বাসি হলে পুনরায় চালু করা যায়। এছাড়াও, এটি কোনও বাশমের উপর নির্ভর করে না।

#!/bin/dash

SCRIPTNAME=$(basename $0)
LOCKDIR="/var/lock/${SCRIPTNAME}"
PIDFILE="${LOCKDIR}/pid"

if ! mkdir $LOCKDIR 2>/dev/null
then
    # lock failed, but check for stale one by checking if the PID is really existing
    PID=$(cat $PIDFILE)
    if ! kill -0 $PID 2>/dev/null
    then
       echo "Removing stale lock of nonexistent PID ${PID}" >&2
       rm -rf $LOCKDIR
       echo "Restarting myself (${SCRIPTNAME})" >&2
       exec "$0" "$@"
    fi
    echo "$SCRIPTNAME is already running, bailing out" >&2
    exit 1
else
    # lock successfully acquired, save PID
    echo $$ > $PIDFILE
fi

trap "rm -rf ${LOCKDIR}" QUIT INT TERM EXIT


echo hello

sleep 30s

echo bye

5

কোনও পরিচিত স্থানে একটি লক ফাইল তৈরি করুন এবং স্ক্রিপ্ট শুরুতে অস্তিত্বের জন্য পরীক্ষা করবেন? স্ক্রিপ্ট কার্যকর হওয়া রোধ করে এমন কেউ যদি কোনও ভুল ত্রুটি খুঁজে বের করার চেষ্টা করে তবে ফাইলটিতে পিআইডি স্থাপন করা সহায়ক হতে পারে।


5

এই উদাহরণটি ম্যান ফ্লকের মধ্যে ব্যাখ্যা করা হয়েছে, তবে এটির জন্য কিছু উন্নতি প্রয়োজন, কারণ আমাদের বাগ এবং প্রস্থান কোডগুলি পরিচালনা করা উচিত:

   #!/bin/bash
   #set -e this is useful only for very stupid scripts because script fails when anything command exits with status more than 0 !! without possibility for capture exit codes. not all commands exits >0 are failed.

( #start subprocess
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200
  if [ "$?" != "0" ]; then echo Cannot lock!; exit 1; fi
  echo $$>>/var/lock/.myscript.exclusivelock #for backward lockdir compatibility, notice this command is executed AFTER command bottom  ) 200>/var/lock/.myscript.exclusivelock.
  # Do stuff
  # you can properly manage exit codes with multiple command and process algorithm.
  # I suggest throw this all to external procedure than can properly handle exit X commands

) 200>/var/lock/.myscript.exclusivelock   #exit subprocess

FLOCKEXIT=$?  #save exitcode status
    #do some finish commands

exit $FLOCKEXIT   #return properly exitcode, may be usefull inside external scripts

আপনি অন্য পদ্ধতি ব্যবহার করতে পারেন, অতীতে আমি যে প্রক্রিয়াগুলি ব্যবহার করেছি তার তালিকা তৈরি করুন। তবে এটি উপরে যে পদ্ধতিটি আরও জটিল। আপনার পিএস দ্বারা প্রক্রিয়াগুলি তালিকাভুক্ত করা উচিত, তার নাম অনুসারে ফিল্টার করুন, পরজীবী নাদ অপসারণের জন্য অতিরিক্ত ফিল্টার গ্রেপ-ভি গ্রেপ অবশেষে এটিকে গ্রেপ-সি দ্বারা গণনা করুন। এবং সংখ্যার সাথে তুলনা করুন। এটি জটিল এবং অনিশ্চিত


1
আপনি ln -s ব্যবহার করতে পারেন, কারণ এটি তখনই সিমলিংক তৈরি করতে পারে যখন কোনও ফাইল বা সিমলিংক উপস্থিত থাকে না, এমকেডিরের মতো। পূর্বে প্রচুর সিস্টেম প্রক্রিয়াগুলি সিমলিঙ্কগুলি ব্যবহার করে, উদাহরণস্বরূপ init বা inetd। সিঙ্কলিঙ্ক প্রক্রিয়া আইডি রাখে, তবে সত্যিই কিছুই দেখায় না। বছরের পর বছর ধরে এই আচরণটি পরিবর্তিত হয়েছিল। প্রক্রিয়াগুলি পশুপাল এবং semaphores ব্যবহার করে।
Znik

5

বিদ্যমান উত্তরগুলি হয় হয় সি এল এল ইউটিলিটির উপর নির্ভর করে flockবা লক ফাইলটি সঠিকভাবে সুরক্ষিত করে না। সমস্ত নন-লিনাক্স সিস্টেমে (যেমন ফ্রিবিএসডি) ফ্লকের ইউটিলিটি উপলব্ধ নেই এবং এনএফএসে সঠিকভাবে কাজ করে না।

সিস্টেম প্রশাসন এবং সিস্টেম বিকাশের আমার প্রথম দিনগুলিতে আমাকে বলা হয়েছিল যে লক ফাইল তৈরির একটি নিরাপদ এবং তুলনামূলকভাবে বহনযোগ্য পদ্ধতিটি টেম্প ফাইল (অর্থাত্ পিআইডি) তে সনাক্তকারী তথ্য লিখতে mkemp(3)বা mkemp(1)তারপরে শক্ত লিঙ্কটি ব্যবহার করে একটি টেম্প ফাইল তৈরি করা ছিল then লক ফাইলটিতে অস্থায়ী ফাইল। লিঙ্কটি সফল হলে, আপনি সফলভাবে লকটি পেয়েছেন।

শেল স্ক্রিপ্টগুলিতে লক ব্যবহার করার সময়, আমি সাধারণত obtain_lock()একটি ভাগ করা প্রোফাইলে একটি ফাংশন রাখি এবং তারপরে স্ক্রিপ্টগুলি থেকে উত্স করি। নীচে আমার লক ফাংশনের উদাহরণ দেওয়া হল:

obtain_lock()
{
  LOCK="${1}"
  LOCKDIR="$(dirname "${LOCK}")"
  LOCKFILE="$(basename "${LOCK}")"

  # create temp lock file
  TMPLOCK=$(mktemp -p "${LOCKDIR}" "${LOCKFILE}XXXXXX" 2> /dev/null)
  if test "x${TMPLOCK}" == "x";then
     echo "unable to create temporary file with mktemp" 1>&2
     return 1
  fi
  echo "$$" > "${TMPLOCK}"

  # attempt to obtain lock file
  ln "${TMPLOCK}" "${LOCK}" 2> /dev/null
  if test $? -ne 0;then
     rm -f "${TMPLOCK}"
     echo "unable to obtain lockfile" 1>&2
     if test -f "${LOCK}";then
        echo "current lock information held by: $(cat "${LOCK}")" 1>&2
     fi
     return 2
  fi
  rm -f "${TMPLOCK}"

  return 0;
};

নিম্নলিখিতটি কীভাবে লক ফাংশনটি ব্যবহার করবেন তার একটি উদাহরণ:

#!/bin/sh

. /path/to/locking/profile.sh
PROG_LOCKFILE="/tmp/myprog.lock"

clean_up()
{
  rm -f "${PROG_LOCKFILE}"
}

obtain_lock "${PROG_LOCKFILE}"
if test $? -ne 0;then
   exit 1
fi
trap clean_up SIGHUP SIGINT SIGTERM

# bulk of script

clean_up
exit 0
# end of script

clean_upআপনার স্ক্রিপ্টের যে কোনও প্রস্থান পয়েন্টে কল করতে ভুলবেন না।

আমি লিনাক্স এবং ফ্রিবিএসডি উভয় পরিবেশে উপরোক্ত ব্যবহার করেছি।


4

কোনও ডেবিয়ান মেশিনকে টার্গেট করার সময় আমি lockfile-progsপ্যাকেজটিকে একটি ভাল সমাধান বলে মনে করি। procmailএছাড়াও একটি lockfileসরঞ্জাম সঙ্গে আসে । তবে মাঝে মাঝে আমি এগুলির কোনওটির সাথেই আটকে থাকি।

এখানে আমার সমাধান যা mkdirবায়ুযুক্ত লকগুলি সনাক্ত করতে পারমাণবিক নেস এবং একটি পিআইডি ফাইল ব্যবহার করে। এই কোডটি বর্তমানে সাইগউইন সেটআপে প্রস্তুত এবং ভালভাবে কাজ করে।

এটি ব্যবহার করার জন্য exclusive_lock_requireযখন আপনার কোনও কিছুর একচেটিয়া অ্যাক্সেসের প্রয়োজন হয় তখনই কল করুন । একটি alচ্ছিক লক নামের প্যারামিটার আপনাকে বিভিন্ন স্ক্রিপ্টগুলির মধ্যে লকগুলি ভাগ করতে দেয়। নিম্ন স্তরের দুটি কার্যও রয়েছে ( exclusive_lock_tryএবং exclusive_lock_retry) আপনার আরও জটিল কিছু প্রয়োজন।

function exclusive_lock_try() # [lockname]
{

    local LOCK_NAME="${1:-`basename $0`}"

    LOCK_DIR="/tmp/.${LOCK_NAME}.lock"
    local LOCK_PID_FILE="${LOCK_DIR}/${LOCK_NAME}.pid"

    if [ -e "$LOCK_DIR" ]
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        if [ ! -z "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2> /dev/null
        then
            # locked by non-dead process
            echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
            return 1
        else
            # orphaned lock, take it over
            ( echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null && local LOCK_PID="$$"
        fi
    fi
    if [ "`trap -p EXIT`" != "" ]
    then
        # already have an EXIT trap
        echo "Cannot get lock, already have an EXIT trap"
        return 1
    fi
    if [ "$LOCK_PID" != "$$" ] &&
        ! ( umask 077 && mkdir "$LOCK_DIR" && umask 177 && echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        # unable to acquire lock, new process got in first
        echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
        return 1
    fi
    trap "/bin/rm -rf \"$LOCK_DIR\"; exit;" EXIT

    return 0 # got lock

}

function exclusive_lock_retry() # [lockname] [retries] [delay]
{

    local LOCK_NAME="$1"
    local MAX_TRIES="${2:-5}"
    local DELAY="${3:-2}"

    local TRIES=0
    local LOCK_RETVAL

    while [ "$TRIES" -lt "$MAX_TRIES" ]
    do

        if [ "$TRIES" -gt 0 ]
        then
            sleep "$DELAY"
        fi
        local TRIES=$(( $TRIES + 1 ))

        if [ "$TRIES" -lt "$MAX_TRIES" ]
        then
            exclusive_lock_try "$LOCK_NAME" > /dev/null
        else
            exclusive_lock_try "$LOCK_NAME"
        fi
        LOCK_RETVAL="${PIPESTATUS[0]}"

        if [ "$LOCK_RETVAL" -eq 0 ]
        then
            return 0
        fi

    done

    return "$LOCK_RETVAL"

}

function exclusive_lock_require() # [lockname] [retries] [delay]
{
    if ! exclusive_lock_retry "$@"
    then
        exit 1
    fi
}

ধন্যবাদ, আমি নিজে সিগুইনে এটি চেষ্টা করেছি এবং এটি সাধারণ পরীক্ষায় উত্তীর্ণ হয়েছে।
এনডেমো

4

যদি এই থ্রেডটিতে ইতিমধ্যে অন্য কোথাও বর্ণিত পালের সীমাবদ্ধতাগুলি আপনার পক্ষে সমস্যা না হয়, তবে এটি কাজ করা উচিত:

#!/bin/bash

{
    # exit if we are unable to obtain a lock; this would happen if 
    # the script is already running elsewhere
    # note: -x (exclusive) is the default
    flock -n 100 || exit

    # put commands to run here
    sleep 100
} 100>/tmp/myjob.lock 

3
আমি ভেবেছি যে আমি এটি চিহ্নিত করব -x (রাইটিং লক) ইতিমধ্যে ডিফল্ট হিসাবে সেট করা আছে।
কেল্ডন অ্যালেন

এবং -nহবে exit 1অবিলম্বে যদি এটা লক পেতে পারে না
Anentropic

ধন্যবাদ কেল্ডন অ্যালিন, আমি ডিফল্ট হওয়ায় "-x" অপসারণের কোডটি আপডেট করেছি।
presto8

3

কিছু unixes আছে lockfileযা খুব ইতিমধ্যে উল্লিখিত অনুরূপ flock

ম্যানপেজ থেকে:

এক বা একাধিক সেমফোর ফাইল তৈরি করতে লকফিল ব্যবহার করা যেতে পারে। যদি লক-ফাইলটি সমস্ত নির্দিষ্ট ফাইল তৈরি করতে না পারে (নির্দিষ্ট ক্রমে), এটি স্লিপটাইম (8 ডিফল্টে ডিফল্ট) সেকেন্ডে অপেক্ষা করে এবং সফল হওয়াতে শেষ ফাইলটি পুনরায় চেষ্টা করে। ব্যর্থতা ফিরে না আসা পর্যন্ত আপনি করার চেষ্টাগুলি উল্লেখ করতে পারেন। যদি পুনরায় চেষ্টা করার সংখ্যা -1 হয় (ডিফল্ট, অর্থাত, -r-1) লকফিল চিরতরে আবার চেষ্টা করবে।


কিভাবে আমরা lockfileইউটিলিটি পাবেন ??
অফিড়মো

lockfileদিয়ে বিতরণ করা হয় procmail। এছাড়াও প্যাকেজ dotlockfileসহ একটি বিকল্প আছে liblockfile। তারা উভয়ই এনএফএসে নির্ভরযোগ্যভাবে কাজ করার দাবি করে।
মিঃ ডেথলেস

3

আসলে যদিও বিএমড্যাক্সের উত্তর প্রায় ভাল, প্রথম লকফায়ালটি পরীক্ষা করার পরে এবং এটি লেখার আগে দ্বিতীয় স্ক্রিপ্টটি চালানোর সামান্য সম্ভাবনা রয়েছে। সুতরাং তারা দুজনেই লক ফাইলটি লিখবে এবং তারা উভয়ই চলবে। এটি নিশ্চিতভাবে কীভাবে কাজ করা যায় তা এখানে:

lockfile=/var/lock/myscript.lock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null ; then
  trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
else
  # or you can decide to skip the "else" part if you want
  echo "Another instance is already running!"
fi

noclobberবিকল্প নিশ্চিত যদি ফাইল আগে থেকেই আছে যে পুনর্নির্দেশ কমান্ড ব্যর্থ হবে করতে হবে। পুনঃনির্দেশ কমান্ডটি আসলে পারমাণবিক - আপনি একটি কমান্ড দিয়ে ফাইলটি লিখে পরীক্ষা করে দেখুন। আপনার ফাইলের শেষে লকফিলটি সরানোর দরকার নেই - এটি ফাঁদে ফেলে দেওয়া হবে। আমি আশা করি এটি এমন লোকদের সহায়তা করে যা এটি পরে পড়বে।

পিএস আমি দেখতে পাইনি যে মাইকেল ইতিমধ্যে প্রশ্নের সঠিক উত্তর দিয়েছেন, যদিও তিনি ট্র্যাক কমান্ডটি অন্তর্ভুক্ত করেননি উদাহরণস্বরূপ Ctrl-C এর সাথে স্ক্রিপ্টটি থামানোর পরে লক ফাইলটি ফেলে দেওয়ার সম্ভাবনা কমাতে। সুতরাং এটি সম্পূর্ণ সমাধান


3

আমি লকফিলস, লকডিয়ারস, বিশেষ লকিং প্রোগ্রামগুলি এবং pidofসমস্ত লিনাক্স ইনস্টলেশনে পাওয়া যায়নি এমনটি সরিয়ে ফেলতে চেয়েছিলাম । সহজতম কোডটিও (বা কমপক্ষে কম কয়েকটি লাইন সম্ভব হিসাবে) পেতে চেয়েছিলেন। ifএক লাইনে সহজ বক্তব্য:

if [[ $(ps axf | awk -v pid=$$ '$1!=pid && $6~/'$(basename $0)'/{print $1}') ]]; then echo "Already running"; exit; fi

1
এটি আমার মেশিনে 'পিএস' আউটপুট সম্পর্কে সংবেদনশীল (উবুন্টু 14.04, / বিএন / পিএসএস থেকে প্রোপস-এনজি সংস্করণ 3.3.9) 'পিএস অ্যাক্স্ফ' কমান্ডটি আসকি গাছের অক্ষর মুদ্রণ করে যা ক্ষেত্রের সংখ্যাগুলিকে ব্যাহত করে। এটি আমার জন্য কাজ করেছে: /bin/ps -a --format pid,cmd | awk -v pid=$$ '/'$(basename $0)'/ { if ($1!=pid) print $1; }'
কুইনিল

2

আমি একটি সাধারণ পদ্ধতির ব্যবহার করি যা বাসি লক ফাইলগুলি পরিচালনা করে।

লক্ষ্য করুন যে উপরের কয়েকটি সমাধান যা পিড সংরক্ষণ করে, পিডটি প্রায় মোড়ানো করতে পারে তা উপেক্ষা করুন। সুতরাং - সঞ্চিত পিডের সাথে কোনও বৈধ প্রক্রিয়া রয়েছে কিনা তা পরীক্ষা করা যথেষ্ট নয়, বিশেষত দীর্ঘস্থায়ী স্ক্রিপ্টগুলির জন্য।

আমি একবারে শুধুমাত্র একটি স্ক্রিপ্ট লক ফাইলটিতে খুলতে এবং লিখতে পারি তা নিশ্চিত করার জন্য নোক্লোবার ব্যবহার করি। তদ্ব্যতীত, আমি লকফাইলে একটি প্রক্রিয়া অনন্যরূপে সনাক্ত করতে পর্যাপ্ত তথ্য সঞ্চয় করি। পিড, পিপিড, lstart হওয়ার প্রক্রিয়াটিকে অনন্যভাবে সনাক্ত করতে আমি ডেটার সেটটিকে সংজ্ঞায়িত করি।

যখন একটি নতুন স্ক্রিপ্ট শুরু হবে, যদি এটি লক ফাইলটি তৈরি করতে ব্যর্থ হয়, তখন এটি যাচাই করে যে লক ফাইলটি তৈরি করার প্রক্রিয়াটি এখনও রয়েছে। যদি তা না হয় তবে আমরা ধরে নিই যে মূল প্রক্রিয়াটি একটি কৃত্রিম মৃত্যুবরণ করেছে, এবং একটি বাসি লক ফাইলটি রেখে গেছে। এরপরে নতুন স্ক্রিপ্টটি লক ফাইলটির মালিকানা গ্রহণ করবে এবং সমস্ত কিছু আবার ভাল।

একাধিক প্ল্যাটফর্ম জুড়ে একাধিক শেল নিয়ে কাজ করা উচিত। দ্রুত, পোর্টেবল এবং সহজ।

#!/usr/bin/env sh
# Author: rouble

LOCKFILE=/var/tmp/lockfile #customize this line

trap release INT TERM EXIT

# Creates a lockfile. Sets global variable $ACQUIRED to true on success.
# 
# Returns 0 if it is successfully able to create lockfile.
acquire () {
    set -C #Shell noclobber option. If file exists, > will fail.
    UUID=`ps -eo pid,ppid,lstart $$ | tail -1`
    if (echo "$UUID" > "$LOCKFILE") 2>/dev/null; then
        ACQUIRED="TRUE"
        return 0
    else
        if [ -e $LOCKFILE ]; then 
            # We may be dealing with a stale lock file.
            # Bring out the magnifying glass. 
            CURRENT_UUID_FROM_LOCKFILE=`cat $LOCKFILE`
            CURRENT_PID_FROM_LOCKFILE=`cat $LOCKFILE | cut -f 1 -d " "`
            CURRENT_UUID_FROM_PS=`ps -eo pid,ppid,lstart $CURRENT_PID_FROM_LOCKFILE | tail -1`
            if [ "$CURRENT_UUID_FROM_LOCKFILE" == "$CURRENT_UUID_FROM_PS" ]; then 
                echo "Script already running with following identification: $CURRENT_UUID_FROM_LOCKFILE" >&2
                return 1
            else
                # The process that created this lock file died an ungraceful death. 
                # Take ownership of the lock file.
                echo "The process $CURRENT_UUID_FROM_LOCKFILE is no longer around. Taking ownership of $LOCKFILE"
                release "FORCE"
                if (echo "$UUID" > "$LOCKFILE") 2>/dev/null; then
                    ACQUIRED="TRUE"
                    return 0
                else
                    echo "Cannot write to $LOCKFILE. Error." >&2
                    return 1
                fi
            fi
        else
            echo "Do you have write permissons to $LOCKFILE ?" >&2
            return 1
        fi
    fi
}

# Removes the lock file only if this script created it ($ACQUIRED is set), 
# OR, if we are removing a stale lock file (first parameter is "FORCE") 
release () {
    #Destroy lock file. Take no prisoners.
    if [ "$ACQUIRED" ] || [ "$1" == "FORCE" ]; then
        rm -f $LOCKFILE
    fi
}

# Test code
# int main( int argc, const char* argv[] )
echo "Acquring lock."
acquire
if [ $? -eq 0 ]; then 
    echo "Acquired lock."
    read -p "Press [Enter] key to release lock..."
    release
    echo "Released lock."
else
    echo "Unable to acquire lock."
fi

আমি আপনাকে আলাদা সমাধানের জন্য +1 দিয়েছি। এছাড়াও এটি এআইএক্স (> পিএস-পিও পিড, পিপিড, লিস্টার্ট $$ | লেজ -1 PS: -o সহ অবৈধ তালিকা) ব্যবহার করে না তবে এইচপি-ইউএক্স (> পিএস-ইও পিড, পিপিড, লিস্টার্ট $$ | লেজ -1 পিএস: অবৈধ বিকল্প - ও)। ধন্যবাদ।
তাগর

2

আপনার স্ক্রিপ্টের শুরুতে এই লাইনটি যুক্ত করুন

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

এটি ম্যান ফ্লকের একটি বয়লারপ্লেট কোড।

আপনি যদি আরও লগিং করতে চান তবে এটি ব্যবহার করুন

[ "${FLOCKER}" != "$0" ] && { echo "Trying to start build from queue... "; exec bash -c "FLOCKER='$0' flock -E $E_LOCKED -en '$0' '$0' '$@' || if [ \"\$?\" -eq $E_LOCKED ]; then echo 'Locked.'; fi"; } || echo "Lock is free. Completing."

এটি flockইউটিলিটি ব্যবহার করে লকগুলি সেট এবং চেক করে । এই কোডটি এটি প্রথমবারে ফ্লোকার ভেরিয়েবলটি পরীক্ষা করে চালানো হয়েছিল কিনা তা সনাক্ত করে, যদি এটি স্ক্রিপ্টের নাম হিসাবে সেট না করা থাকে, তবে এটি পুনরায় পুনরুত্প্রকারভাবে ঝাঁক ব্যবহার করে এবং FLOCKER ভেরিয়েবল আরম্ভকরণের চেষ্টা করে, যদি FLOCKER সঠিকভাবে সেট করা থাকে, তবে পূর্ববর্তী পুনরাবৃত্তিতে ফ্লক করুন সফল এবং এটি এগিয়ে যেতে ঠিক আছে। লক ব্যস্ত থাকলে, এটি কনফিগারযোগ্য প্রস্থান কোডের সাথে ব্যর্থ হয়।

এটি ডেবিয়ান 7 এ কাজ করছে না বলে মনে হচ্ছে, তবে পরীক্ষামূলক ইউজ-লিনাক্স 2.25 প্যাকেজটি নিয়ে আবার কাজ করবে বলে মনে হচ্ছে। এটি "ফ্লক: ... টেক্সট ফাইল ব্যস্ত" লিখেছেন। এটি আপনার স্ক্রিপ্টে লেখার অনুমতি অক্ষম করে ওভাররাইড করা যেতে পারে।


1

পিআইডি এবং লকফিলগুলি অবশ্যই সবচেয়ে নির্ভরযোগ্য। আপনি যখন প্রোগ্রামটি চালানোর চেষ্টা করছেন, এটি লকফাইলে যা যা এবং এটি বিদ্যমান থাকলে তা পরীক্ষা করতে পারে psযে প্রক্রিয়াটি এখনও চলছে কিনা তা দেখতে এটি ব্যবহার করতে পারে । যদি এটি না হয় তবে স্ক্রিপ্টটি শুরু করতে পারে, লকফাইলে থাকা পিআইডিটিকে নিজস্ব হিসাবে আপডেট করে।


1

আমি দেখতে পেয়েছি যে কমপক্ষে আমার ব্যবহারের ক্ষেত্রে বিএমড্যাকের সমাধানটি সবচেয়ে ব্যবহারিক। ফ্লক এবং লকফিল ব্যবহার করে স্ক্রিপ্টটি সমাপ্ত হলে লকফায়ালটি আরএম ব্যবহার করে মুছে ফেলার উপর নির্ভর করে, যা সর্বদা গ্যারান্টিযুক্ত হতে পারে না (যেমন, কিল -9)।

আমি বিএমড্যাকের সমাধান সম্পর্কে একটি ছোটখাটো জিনিস পরিবর্তন করব: এটি লক ফাইলটি সরিয়ে ফেলার বিষয়টি তুলে ধরেছে, এটি উল্লেখ না করেই যে এই سيمফোরের নিরাপদ কাজের জন্য এটি অপ্রয়োজনীয়। তাঁর কিল -0-এর ব্যবহার নিশ্চিত করে যে একটি মৃত প্রক্রিয়ার জন্য একটি পুরানো লকফিল কেবল উপেক্ষা / অতিরিক্ত লিখিত হবে।

আমার সরলিকৃত সমাধানটি কেবলমাত্র আপনার সিঙ্গলটনের শীর্ষে নিম্নলিখিতটি যুক্ত করার জন্য:

## Test the lock
LOCKFILE=/tmp/singleton.lock 
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
    echo "Script already running. bye!"
    exit 
fi

## Set the lock 
echo $$ > ${LOCKFILE}

অবশ্যই, এই স্ক্রিপ্টটিতে এখনও ত্রুটি রয়েছে যা একই সময়ে শুরু হওয়ার সম্ভাবনা রয়েছে এমন প্রক্রিয়াগুলির একটি রেসের ঝুঁকি রয়েছে, কারণ লক পরীক্ষা এবং সেট অপারেশনগুলি কোনও একক পারমাণবিক ক্রিয়া নয়। তবে লুনাথের এমকেডির ব্যবহারের প্রস্তাবিত সমাধানটিতে একটি ত্রুটি রয়েছে যে একটি নিহত স্ক্রিপ্টটি ডিরেক্টরিতে রেখে যেতে পারে, ফলে অন্যান্য দৃষ্টান্তগুলি চলতে বাধা দেয়।


1

Semaphoric ইউটিলিটি ব্যবহার flock(যেমন presto8 করে উপরের আলোচনা, যেমন) একটি বাস্তবায়ন কাউন্টিং সেমফোর্ । এটি আপনার চাইলে যে কোনও নির্দিষ্ট সংখ্যক সমসাময়িক প্রক্রিয়া সক্ষম করে। আমরা বিভিন্ন সারিবদ্ধ কর্মী প্রক্রিয়াগুলির সম্মতি স্তরকে সীমাবদ্ধ করতে এটি ব্যবহার করি।

এটি sem এর মতো তবে অনেক বেশি হালকা ওজনের। (সম্পূর্ণ প্রকাশ: Sem সন্ধানের পরে এটি লিখেছিলাম এটি আমাদের প্রয়োজনের জন্য খুব ভারী ছিল এবং সেখানে একটি সাধারণ গণনা সেমফোর ইউটিলিটি উপলব্ধ ছিল না।)


1

পালের সাথে একটি উদাহরণ (1) তবে সাব শীল ছাড়াই। flock () এডি ফাইল / tmp / foo কখনই সরানো হয় না, তবে এটি flock () এবং un-flock () এড হওয়ার সাথে কিছু যায় আসে না।

#!/bin/bash

exec 9<> /tmp/foo
flock -n 9
RET=$?
if [[ $RET -ne 0 ]] ; then
    echo "lock failed, exiting"
    exit
fi

#Now we are inside the "critical section"
echo "inside lock"
sleep 5
exec 9>&- #close fd 9, and release lock

#The part below is outside the critical section (the lock)
echo "lock released"
sleep 5

1

ইতিমধ্যে এক মিলিয়ন বার উত্তর দেওয়া হয়েছে, তবে অন্য উপায়, বাহ্যিক নির্ভরতার প্রয়োজন ছাড়াই:

LOCK_FILE="/var/lock/$(basename "$0").pid"
trap "rm -f ${LOCK_FILE}; exit" INT TERM EXIT
if [[ -f $LOCK_FILE && -d /proc/`cat $LOCK_FILE` ]]; then
   // Process already exists
   exit 1
fi
echo $$ > $LOCK_FILE

প্রতিবার এটি বর্তমান পিআইডি ($$) লকফাইলে এবং স্ক্রিপ্ট স্টার্টআপ চেকগুলিতে সর্বশেষ পিআইডি সহ কোনও প্রক্রিয়া চলছে কিনা তা লেখায়।


1
ট্র্যাপ কল ব্যতীত (বা কমপক্ষে সাধারণ ক্ষেত্রে শেষের দিকে কোনও ক্লিনআপ) ছাড়াই আপনার কাছে মিথ্যা পজিটিভ বাগ রয়েছে যেখানে শেষ দৌড়ের পরে লকফিলটি প্রায় বাকি রয়েছে এবং পরে পিআইডি অন্য একটি প্রক্রিয়া দ্বারা পুনরায় ব্যবহার করা হয়েছে। (এবং সবচেয়ে খারাপ ক্ষেত্রে, এটি আপাচের মতো দীর্ঘ চলমান প্রক্রিয়াটিকে উপহার দেওয়া হয়েছে ....)
ফিলিপ চেন্ট্রেইইল

1
আমি সম্মত, আমার পদ্ধতির ত্রুটিযুক্ত, এটি একটি ফাঁদ প্রয়োজন। আমি আমার সমাধান আপডেট করেছি। আমি এখনও বাহ্যিক নির্ভরতা না রাখতে পছন্দ করি।
ফিলিডর উইস

1

প্রক্রিয়াটির লকটি ব্যবহার করা আরও শক্তিশালী এবং কদর্য প্রস্থানগুলিও যত্ন করে। লক_ফাইলে যতক্ষণ প্রক্রিয়া চলছে ততক্ষণ খোলা রাখা হবে। প্রক্রিয়াটি উপস্থিত হয়ে গেলে এটি (শেল দ্বারা) বন্ধ হয়ে যাবে (এটি মারা গেলেও)। আমি এটি খুব দক্ষ বলে মনে করেছি:

lock_file=/tmp/`basename $0`.lock

if fuser $lock_file > /dev/null 2>&1; then
    echo "WARNING: Other instance of $(basename $0) running."
    exit 1
fi
exec 3> $lock_file 

1

আমি স্ক্রিপ্টের একেবারে শুরুতে অনেলাইনার @ ব্যবহার করি:

#!/bin/bash

if [[ $(pgrep -afc "$(basename "$0")") -gt "1" ]]; then echo "Another instance of "$0" has already been started!" && exit; fi
.
the_beginning_of_actual_script

মেমোরিতে প্রক্রিয়াটির উপস্থিতি দেখে ভাল হয় (প্রক্রিয়াটির স্থিতিটি যাই হোক না কেন); তবে এটি আমার জন্য কাজ করে।


0

পালের পথই চলার পথ। স্ক্রিপ্টটি হঠাৎ মারা গেলে কী ঘটে তা ভেবে দেখুন। পশুর ক্ষেত্রে আপনি কেবল ঝাঁক ঝাঁকিয়েছেন, তবে এটি কোনও সমস্যা নয়। এছাড়াও, নোট করুন যে একটি অশুভ কৌশল হ'ল স্ক্রিপ্টে নিজেই একটি ঝাঁক নিয়ে যাওয়া .. তবে অবশ্যই অনুমতি সংক্রান্ত সমস্যার জন্য আপনাকে পুরো বাষ্পে চালিয়ে যেতে দেয়।


0

দ্রুত এবং ময়লা?

#!/bin/sh

if [ -f sometempfile ]
  echo "Already running... will now terminate."
  exit
else
  touch sometempfile
fi

..do what you want here..

rm sometempfile

7
এটি কীভাবে ব্যবহৃত হবে তার উপর নির্ভর করে এটি কোনও সমস্যা হতে পারে বা নাও হতে পারে তবে লকটির জন্য পরীক্ষা করে এটি তৈরি করার মধ্যে একটি দৌড়ের শর্ত রয়েছে, যাতে দুটি স্ক্রিপ্ট একই সাথে শুরু করা যায় could যদি প্রথমটি সমাপ্ত হয়, অন্যটি লক ফাইল না দিয়ে চলমান থাকবে।
টিমবি

3
সি নিউজ, যা আমাকে পোর্টেবল শেল স্ক্রিপ্টিং সম্পর্কে অনেক কিছু শিখিয়েছিল, একটি লক তৈরি করত $$ ফাইলটি, এবং তারপরে এটিকে "লক" দিয়ে লিঙ্ক করার চেষ্টা করে - যদি লিঙ্কটি সফল হয় তবে আপনার তালাটি ছিল, অন্যথায় আপনি লকটি সরিয়ে ফেলেছেন $$ এবং প্রস্থান।
পল টমবলিন

এটি করার সত্যিই ভাল উপায়, যদি আপনি এখনও কিছু ভুল হয়ে যায় এবং লকফিলটি মোছা না হয় তবে আপনি নিজেই লকফিলটি সরিয়ে ফেলতে হবে না suffer
ম্যাথু শার্লে

2
দ্রুত এবং নোংরা, সে যা চেয়েছিল :)
আউপাজো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.