शेल स्क्रिप्ट में सही लॉकिंग?


66

कभी-कभी आपको यह सुनिश्चित करना होता है कि एक ही समय में शेल स्क्रिप्ट का केवल एक उदाहरण चल रहा है।

उदाहरण के लिए एक क्रॉन जॉब जिसे क्रोन के माध्यम से निष्पादित किया जाता है जो अपने आप लॉकिंग प्रदान नहीं करता है (उदाहरण के लिए डिफ़ॉल्ट सोलारिस क्रोन)।

लॉकिंग को लागू करने के लिए एक सामान्य पैटर्न इस तरह कोड है:

#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then            # 'test' -> race begin
  echo Job is already running\!
  exit 6
fi
touch $LOCK                      # 'set'  -> race end
# do some work
rm $LOCK

बेशक, ऐसे कोड में एक दौड़ की स्थिति है। एक समय खिड़की है जहां दो उदाहरणों का निष्पादन दोनों पंक्ति 3 के बाद अग्रिम कर सकते हैं इससे पहले कि $LOCKफ़ाइल को छूने में सक्षम हो ।

क्रॉन जॉब के लिए यह आमतौर पर एक समस्या नहीं है क्योंकि आपके पास दो इनवोकेशन के बीच कुछ मिनटों का अंतराल है।

लेकिन चीजें गलत हो सकती हैं - उदाहरण के लिए जब एनएफएस सर्वर पर लॉकफाइल होता है - जो लटका रहता है। उस स्थिति में कई क्रॉन जॉब्स लाइन 3 पर ब्लॉक हो सकते हैं और कतार में खड़े हो सकते हैं। यदि एनएफएस सर्वर फिर से सक्रिय है, तो आपके पास समानांतर चलने वाली नौकरियों का झुंड है।

वेब पर खोज करने पर मुझे टूल लॉकरन मिला जो उस समस्या के अच्छे समाधान की तरह लगता है। इसके साथ आप एक स्क्रिप्ट चलाते हैं जिसे इस तरह लॉक करने की आवश्यकता होती है:

$ lockrun --lockfile=/var/tmp/mylock myscript.sh

आप इसे एक आवरण में रख सकते हैं या अपने क्रॉस्टब से उपयोग कर सकते हैं।

यह lockf()(POSIX) का उपयोग करता है यदि उपलब्ध है और वापस flock()(BSD) में आता है। और lockf()एनएफएस पर समर्थन अपेक्षाकृत व्यापक होना चाहिए।

के विकल्प हैं lockrun?

अन्य क्रोन डेमॉन के बारे में क्या? क्या कॉमन तरीके से कॉन लॉकिंग करने वाले कॉमन कॉर्ड हैं? विक्सी क्रोनड (डिबियन / उबंटू सिस्टम पर डिफ़ॉल्ट) के मैन पेज पर एक त्वरित नज़र लॉकिंग के बारे में कुछ भी नहीं दिखाती है।

यह एक अच्छा विचार की तरह एक उपकरण शामिल करने के लिए किया जाएगा lockrunमें coreutils ?

मेरी राय में यह बहुत करने के लिए इसी तरह की एक विषय को लागू करता है timeout, niceऔर दोस्तों।


4
मूर्त रूप से, और दूसरों के लाभ के लिए, जो आपके प्रारंभिक पैटर्न गुड एनफ (टीएम) पर विचार कर सकते हैं, उस शेल कोड को संभवतः killएड को तब टाॅप ट्रैप करना चाहिए , जब एड; और यह अच्छा लगता है कि किसी व्यक्ति को लॉक करने के बजाय केवल उसे छूने से अच्छा है।
उलरिच श्वार्ज


@ शॉन, वास्तव में नहीं, क्रोन और एनएफएस का उल्लेख नहीं करता है।
अधिकतम

SO पर संबंधित प्रश्न: stackoverflow.com/questions/185451/…
maxschlepzig

1
@ बहुत स्पष्ट रूप से, एनएफएस लॉकफाइल में एक पीआईडी ​​संग्रहीत करना बहुत कम मूल्य जोड़ता है। यहां तक ​​कि होस्टनाम को जोड़ना अभी भी वास्तव में एक जीवित प्रक्रिया के लिए जाँच करने में मदद नहीं करता है
रोआमा

जवाबों:


45

यहां शेल स्क्रिप्ट में लॉक करने का एक और तरीका है जो आपको ऊपर वर्णित दौड़ की स्थिति को रोक सकता है, जहां दो नौकरियां दोनों लाइन पास हो सकती हैं। 3. noclobberविकल्प ksh और bash में काम करेगा। उपयोग न करें set noclobberक्योंकि आपको csh / tcsh में स्क्रिप्टिंग नहीं करनी चाहिए। ;)

lockfile=/var/tmp/mylock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then

        trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

        # do stuff here

        # clean up after yourself, and release your trap
        rm -f "$lockfile"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi

एनएफएस पर लॉकिंग के साथ वाईएमएमवी (आप जानते हैं, जब एनएफएस सर्वर उपलब्ध नहीं हैं), लेकिन सामान्य तौर पर यह पहले की तुलना में बहुत अधिक मजबूत है। (10 साल पहले)

यदि आपके पास क्रोन नौकरियां हैं जो एक ही समय में एक ही काम करती हैं, तो कई सर्वरों से, लेकिन आपको वास्तव में चलाने के लिए केवल 1 उदाहरण की आवश्यकता है, ऐसा कुछ आपके लिए काम कर सकता है।

मुझे लॉकरून के साथ कोई अनुभव नहीं है, लेकिन स्क्रिप्ट से पहले पूर्व-सेट लॉक वातावरण होने से वास्तव में चलने में मदद मिल सकती है। या यह नहीं हो सकता है। आप सिर्फ एक लिपि में अपनी स्क्रिप्ट के बाहर लॉकफाइल के लिए परीक्षण सेट कर रहे हैं, और सैद्धांतिक रूप से, क्या आप सिर्फ एक ही दौड़ की स्थिति नहीं मार सकते हैं यदि दो नौकरियों को लॉकरुन द्वारा ठीक उसी समय कहा जाता है, जैसे कि 'अंदर' के साथ। पटकथा 'समाधान?

फ़ाइल लॉकिंग बहुत सम्मान प्रणाली व्यवहार वैसे भी है, और कोई भी स्क्रिप्ट जो लॉकफ़ाइल के अस्तित्व के लिए जाँच नहीं करता है चलने से पहले वे जो कुछ भी करने जा रहे हैं। सिर्फ लॉकफाइल टेस्ट, और उचित व्यवहार में डालकर, आप 100% नहीं तो 99% संभावित समस्याओं को हल करेंगे।

यदि आप लॉकफ़ाइल दौड़ की स्थिति में बहुत अधिक भाग लेते हैं, तो यह एक बड़ी समस्या का सूचक हो सकता है, जैसे कि आपकी नौकरियां सही समय पर नहीं होना, या शायद अगर अंतराल नौकरी पूरी करने के लिए उतना महत्वपूर्ण नहीं है, तो शायद आपकी नौकरी का नियमन किया जाना बेहतर है। ।


EDIT BELOW - 2016-05-06 (यदि आप KSH88 का उपयोग कर रहे हैं)


नीचे दिए गए @ क्लिंट पाचल की टिप्पणी के आधार पर, यदि आप ksh88 का उपयोग करते हैं, तो mkdirइसके बजाय का उपयोग करें noclobber। यह ज्यादातर एक संभावित दौड़ की स्थिति को कम करता है, लेकिन इसे पूरी तरह से सीमित नहीं करता है (हालांकि जोखिम न्यूनतम है)। अधिक जानकारी के लिए नीचे दिए गए लिंक को क्लिंट ने पढ़ा ।

lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid

if ( mkdir ${lockdir} ) 2> /dev/null; then
        echo $$ > $pidfile
        trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
        # do stuff here

        # clean up after yourself, and release your trap
        rm -rf "$lockdir"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi

और, एक अतिरिक्त लाभ के रूप में, यदि आपको अपनी स्क्रिप्ट में tmpfiles बनाने की आवश्यकता है, तो आप lockdirउनके लिए निर्देशिका का उपयोग कर सकते हैं, यह जानकर कि स्क्रिप्ट से बाहर निकलने पर उन्हें साफ किया जाएगा।

अधिक आधुनिक बैश के लिए, शीर्ष पर स्थित noclobber विधि उपयुक्त होनी चाहिए।


1
नहीं, लॉकरुन के साथ आपको कोई समस्या नहीं है - जब कोई एनएफएस सर्वर हैंग होता है, तो सिस्टम कॉल में सभी लॉकरुन कॉल लटकाएंगे (कम से कम) lockf()- जब यह बैकअप होता है तो सभी प्रक्रियाएं फिर से शुरू हो जाती हैं, लेकिन केवल एक प्रक्रिया लॉक जीत जाएगी। कोई दौड़ की स्थिति नहीं। मैं क्रोनॉजर्स के साथ ऐसी समस्याओं में नहीं भागता हूं - विपरीत स्थिति है - लेकिन यह एक समस्या है जब यह हिट होता है तो इसमें बहुत दर्द पैदा करने की क्षमता होती है।
maxschlepzig

1
मैंने इस उत्तर को स्वीकार कर लिया है क्योंकि यह विधि सुरक्षित है और अब तक सबसे सुरुचिपूर्ण है। मैं एक छोटे संस्करण का सुझाव देता हूं: set -o noclobber && echo "$$" > "$lockfile"जब शेल नोकब्लबर विकल्प का समर्थन नहीं करता है तो एक सुरक्षित वापसी पाने के लिए।
मैक्सक्लेपजिग

3
अच्छा जवाब है, लेकिन आपको यह सुनिश्चित करने के लिए भी लॉक-फ़ील में 'मार -0' मान लेना चाहिए कि लॉक बनाने वाली प्रक्रिया अभी भी मौजूद है।
निगेल हॉर्न

1
noclobberविकल्प की स्थिति दौड़ होने का खतरा हो सकता है। विचार के लिए कुछ खाने के लिए mywiki.wooledge.org/BashFAQ/045 देखें ।
क्लिंट पाचल

2
नोट: ksh88 में उपयोग noclobber(या -C) काम नहीं करता है क्योंकि ksh88 के O_EXCLलिए उपयोग नहीं करता है noclobber। यदि आप एक नए शेल के साथ चल रहे हैं, तो आप ठीक हो सकते हैं ...
jrw32982

14

मैं हार्ड लिंक का उपयोग करना पसंद करता हूं।

lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
    echo locked
else
    echo locked by $(<$lockfile)
    rm $tmpfile
    exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to

हार्ड लिंक NFS पर परमाणु हैं और अधिकांश भाग के लिए, mkdir भी है । व्यावहारिक स्तर पर इसका उपयोग करना mkdir(2)या link(2)इसके बारे में समान होना; मैं सिर्फ हार्ड लिंक का उपयोग करना पसंद करता हूं क्योंकि एनएफएस के अधिक कार्यान्वयन ने परमाणु की तुलना में परमाणु लिंक की अनुमति दी है mkdir। एनएफएस के आधुनिक रिलीज के साथ, आपको या तो उपयोग करने की चिंता नहीं करनी चाहिए।


12

मैं समझता हूं कि mkdirपरमाणु है, इसलिए शायद:

lockdir=/var/tmp/myapp
if mkdir $lockdir; then
  # this is a new instance, store the pid
  echo $$ > $lockdir/PID
else
  echo Job is already running, pid $(<$lockdir/PID) >&2
  exit 6
fi

# then set traps to cleanup upon script termination 
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15

ठीक है, लेकिन मुझे यह पता नहीं चल पाया है कि क्या mkdir()NFS (> = 3) परमाणु से मानकीकृत है।
maxschlepzig

2
@maxschlepzig RFC 1813 स्पष्ट रूप mkdirसे परमाणु होने का आह्वान नहीं करता (यह करता है rename)। व्यवहार में, यह ज्ञात है कि कुछ कार्यान्वयन नहीं हैं। संबंधित: GNU आर्च के लेखक द्वारा योगदान सहित एक दिलचस्प सूत्र
ग्लीस

8

एक आसान तरीका यह है कि lockfileआमतौर पर procmailपैकेज के साथ आने का उपयोग करें ।

LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0

# here the actual job

rm -f "$LOCKFILE"

5

semजो GNU parallelटूल्स के हिस्से के रूप में आता है, वह हो सकता है:

sem [--fg] [--id <id>] [--semaphoretimeout <secs>] [-j <num>] [--wait] command

जैसे की:

sem --id my_semaphore --fg "echo 1 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 2 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 3 ; date ; sleep 3" &

outputting:

1
Thu 10 Nov 00:26:21 UTC 2016
2
Thu 10 Nov 00:26:24 UTC 2016
3
Thu 10 Nov 00:26:28 UTC 2016

ध्यान दें कि आदेश की गारंटी नहीं है। इसके अलावा आउटपुट तब तक प्रदर्शित नहीं होता है जब तक कि यह खत्म (परेशान) न हो। लेकिन फिर भी, यह सबसे संक्षिप्त तरीका है जिसे मैं लॉकफ़ाइल्स और रिट्रीट और क्लीनअप के बारे में चिंता किए बिना समवर्ती निष्पादन के खिलाफ गार्ड करना जानता हूं।


क्या semमध्य-निष्पादन के दौरान शॉट को लॉक करने की पेशकश की जाती है?
रोज़ा

2

मैं उपयोग करता हूं dtach

$ dtach -n /tmp/socket long_running_task ; echo $?
0
$ dtach -n /tmp/socket long_running_task ; echo $?
dtach: /tmp/socket: Address already in use
1

1

मैं अपनी बैश लिपियों में ताले को प्रबंधित करने के लिए कमांड-लाइन टूल "फ्लॉक" का उपयोग करता हूं, जैसा कि यहां और यहां वर्णित है । मैंने इस सरल विधि का उपयोग झुंड के मेन्यू से किया है, कुछ उपसमूह में कमांड चलाने के लिए ...

   (
     flock -n 9
     # ... commands executed under lock ...
   ) 9>/var/lock/mylockfile

उस उदाहरण में, यह 1 के एक्जिट कोड के साथ विफल हो जाता है अगर यह लॉकफाइल का अधिग्रहण नहीं कर सकता है। लेकिन झुंड को उन तरीकों से भी इस्तेमाल किया जा सकता है जिन्हें उप-शेल में चलाने के लिए कमांड की आवश्यकता नहीं होती है :-)



1
बीएसडी का एक समान उपकरण है, "लॉकफ़"।
डबियसजिम

2
@dubiousjim, BSD लॉकफ भी कॉल करता है flock()और इस प्रकार NFS पर समस्याग्रस्त है। Btw, इस बीच, लिनक्स पर झुंड () अब वापस आता है fcntl()जब फ़ाइल एनएफएस माउंट पर स्थित होती है, इस प्रकार, केवल लिनक्स एनएफएस वातावरण में flock()अब एनएफएस पर काम करता है।
मैक्सक्लेपजिग

1

फ़ाइल का उपयोग न करें।

यदि आपकी स्क्रिप्ट इस तरह निष्पादित की जाती है:

bash my_script

यदि आप इसका उपयोग करके चल रहे हैं, तो आप पता लगा सकते हैं:

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

Hm, ps चेकिंग कोड भीतर से चलता है my_script? मामले में एक और उदाहरण चल रहा है - running_procजिसमें दो मिलान लाइनें नहीं हैं? मुझे यह विचार पसंद है, लेकिन निश्चित रूप से - आपको झूठे परिणाम मिलेंगे जब कोई अन्य उपयोगकर्ता उसी नाम से एक स्क्रिप्ट चला रहा हो ...
maxschlepzig

3
इसमें एक दौड़ की स्थिति भी शामिल है: यदि 2 उदाहरण समानांतर में पहली पंक्ति को निष्पादित करते हैं, तो किसी को भी 'लॉक' नहीं मिलता है और दोनों स्थिति से बाहर निकलते हैं। 6. यह एक प्रकार का एक राउंड आपसी भुखमरी होगी । Btw, मुझे यकीन नहीं है कि आप अपने उदाहरण के $!बजाय क्यों उपयोग $$करते हैं।
अधिकतम

@maxschlepzig वास्तव में गलत $ के बारे में खेद है! बनाम $ $
मेंढक

@maxschlepzig स्क्रिप्ट चलाने वाले कई उपयोगकर्ताओं को संभालने के लिए euser = -o तर्क जोड़ें।
मेंढकप्रस्त fro

कई लाइनों को रोकने के लिए @ maxschlepzig आप grep, या अतिरिक्त "फ़िल्टर" (जैसे grep -v $$) के तर्क भी बदल सकते हैं । मूल रूप से मैं समस्या को एक अलग दृष्टिकोण प्रदान करने का प्रयास कर रहा था।
मेंढकप्रस्त fro

1

वास्तविक उपयोग के लिए, आपको शीर्ष मतदान उत्तर का उपयोग करना चाहिए ।

हालाँकि, मैं कुछ विभिन्न टूटे हुए और अर्ध-काम करने योग्य दृष्टिकोणों का उपयोग करना psऔर उनके पास कई कैविएट पर चर्चा करना चाहता हूं , क्योंकि मैं देखता हूं कि लोग उनका उपयोग करते हैं।

यह उत्तर वास्तव में " शेल में लॉकिंग का उपयोग करने psऔर grepसंभालने के लिए क्यों नहीं ?"

टूटे हुए दृष्टिकोण # 1

सबसे पहले, एक अन्य उत्तर में दिया गया एक दृष्टिकोण, जिसमें इस तथ्य के बावजूद कुछ बदलाव होते हैं कि यह (और कभी नहीं) काम कर सकता है और स्पष्ट रूप से परीक्षण नहीं किया गया है:

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

आइए वाक्यविन्यास त्रुटियों और टूटे हुए psतर्कों को ठीक करें और प्राप्त करें:

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

यह स्क्रिप्ट हमेशा 6 से बाहर होगी , हर बार, चाहे आप इसे कैसे भी चलाएं।

यदि आप इसे चलाते हैं ./myscript, तो psआउटपुट बस होगा 12345 -bash, जो आवश्यक स्ट्रिंग से मेल नहीं खाता है 12345 bash ./myscript, ताकि विफल हो जाए।

यदि आप इसे चलाते हैं bash myscript, तो चीजें अधिक दिलचस्प हो जाती हैं। बाश प्रक्रिया पाइपलाइन चलाने के लिए कांटे , और बच्चा खोल psऔर चलाता है grep। दोनों मूल खोल और बच्चे खोल में दिखाई देगा psउत्पादन, कुछ इस तरह:

25793 bash myscript
25795 bash myscript

यह अपेक्षित आउटपुट नहीं है $$ bash $0, इसलिए आपकी स्क्रिप्ट बाहर निकल जाएगी।

टूटा हुआ दृष्टिकोण # 2

अब उस उपयोगकर्ता के लिए सभी निष्पक्षता में जो टूटे हुए दृष्टिकोण # 1 को लिखता है, जब मैंने पहली बार ऐसा करने की कोशिश की थी, तो मैंने खुद भी कुछ ऐसा ही किया था:

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

यह लगभग काम करता है। लेकिन पाइप को चलाने के लिए फोर्किंग का तथ्य यह बंद कर देता है। तो यह हमेशा बाहर निकल जाएगा, भी।

अविश्वसनीय दृष्टिकोण # 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

यह संस्करण पाइप लाइन में समस्या को टालने से बचता है # 2 सबसे पहले उन सभी पीआईडी ​​को प्राप्त करके जो उनके कमांड लाइन तर्कों में वर्तमान स्क्रिप्ट है, और फिर उस स्क्रिप्ट को फ़िल्टर करके, अलग से, वर्तमान स्क्रिप्ट के पीआईडी ​​को छोड़ना है।

यह काम कर सकता है ... कोई अन्य प्रक्रिया प्रदान करना एक कमांड लाइन से मेल खाता है $0, और स्क्रिप्ट प्रदान करना हमेशा उसी तरह से कहा जाता है (जैसे कि यदि यह एक रिश्तेदार पथ के साथ कहा जाता है और फिर एक निरपेक्ष पथ है, तो बाद का उदाहरण पूर्व को नोटिस नहीं करेगा। )।

अविश्वसनीय दृष्टिकोण # 4

तो क्या हुआ अगर हम पूरी कमांड लाइन की जाँच करना छोड़ देते हैं, क्योंकि हो सकता है कि वह वास्तव में चलने वाली स्क्रिप्ट का संकेत न दे, और lsofइस स्क्रिप्ट को खोलने वाली सभी प्रक्रियाओं को खोजने के बजाय जाँच करें ?

ठीक है, हाँ, यह दृष्टिकोण वास्तव में बहुत बुरा नहीं है:

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

बेशक, यदि स्क्रिप्ट की एक प्रति चल रही है, तो नया उदाहरण ठीक शुरू हो जाएगा और आपके पास दो प्रतियां चल रही होंगी ।

या यदि रनिंग स्क्रिप्ट को संशोधित किया गया है (उदाहरण के साथ विम के साथ git checkout), तो स्क्रिप्ट का "नया" संस्करण बिना किसी समस्या के शुरू होगा, क्योंकि विम और git checkoutपरिणाम में दोनों एक नई फ़ाइल (एक नया इनोड) के स्थान पर आते हैं। पुराना वाला।

हालांकि, यदि स्क्रिप्ट को कभी भी संशोधित नहीं किया गया है और कभी भी कॉपी नहीं किया गया है, तो यह संस्करण बहुत अच्छा है। कोई दौड़ की स्थिति नहीं है क्योंकि चेक तक पहुँचने से पहले ही स्क्रिप्ट फ़ाइल को खोलना पड़ता है।

यदि किसी अन्य प्रक्रिया में स्क्रिप्ट फ़ाइल खुली है, तो भी झूठी सकारात्मक हो सकती है, लेकिन ध्यान दें कि भले ही यह विम में संपादन के लिए खुला हो, लेकिन विम वास्तव में स्क्रिप्ट फ़ाइल को खुला नहीं रखता है, जिससे झूठी सकारात्मकता उत्पन्न नहीं होगी।

लेकिन याद रखें, यदि स्क्रिप्ट को संपादित या कॉपी किया जा सकता है तो इस दृष्टिकोण का उपयोग न करें क्योंकि आपको झूठी नकारात्मक मिलेंगी अर्थात एक ही बार में कई इंस्टेंसेस चल रहे हैं - इसलिए यह तथ्य कि विम के साथ एडिटिंग किसी भी तरह की झूठी सकारात्मकता नहीं देता है। आप को। मैं, यह उल्लेख है, हालांकि, क्योंकि दृष्टिकोण # 3 करता झूठे सकारात्मक देना (यानी शुरू करने के लिए मना कर दिया) यदि आप स्क्रिप्ट विम के साथ खुला है।

तो क्या करें, फिर?

इस प्रश्न का शीर्ष-मतदान उत्तर एक अच्छा ठोस दृष्टिकोण देता है।

शायद आप एक बेहतर लिख सकते हैं ... लेकिन यदि आप उपरोक्त सभी दृष्टिकोणों के साथ सभी समस्याओं और गुटों को नहीं समझते हैं, तो आप उन सभी को टालने वाली एक लॉकिंग विधि लिखने की संभावना नहीं रखते हैं।


0

FLOM (Free LOck Manager) टूल का उपयोग करना , कमांडिंग कमांडिंग चलाना जितना आसान हो जाता है

flom -- command_to_serialize

FLOM आपको अधिक स्पष्ट उपयोग के मामलों (वितरित लॉकिंग, पाठकों / लेखकों, संख्यात्मक संसाधनों, आदि ...) को लागू करने की अनुमति देता है जैसा कि यहाँ बताया गया है: http://sourceforge.net/p/flom/wiki/FLOM%20by%20exam/


0

यहाँ कुछ ऐसा है जो मैं कभी-कभी मशीन पर किसी भी नौकरी के लिए दौड़ की स्थिति को आसानी से संभालने के लिए सर्वर पर जोड़ता हूं। यह टिम कैनेडी के पद के लिए सिमेरिलर है, लेकिन इस तरह से आपको प्रत्येक बैश स्क्रिप्ट में केवल एक पंक्ति जोड़कर दौड़ से निपटने की आवश्यकता है।

नीचे दी गई सामग्री को उदा / ऑप्ट / रेसकैचर / रेसकैचर में डालें:

ZPROGRAMNAME=$(readlink -f $0)
EZPROGRAMNAME=`echo $ZPROGRAMNAME | sed 's/\//_/g'`
EZMAIL="/usr/bin/mail"
EZCAT="/bin/cat"

if  [ -n "$EZPROGRAMNAME" ] ;then
        EZPIDFILE=/tmp/$EZPROGRAMNAME.pid
        if [ -e "$EZPIDFILE" ] ;then
                EZPID=$($EZCAT $EZPIDFILE)
                echo "" | $EZMAIL -s "$ZPROGRAMNAME already running with pid $EZPID"  alarms@someemail.com >>/dev/null
                exit -1
        fi
        echo $$ >> $EZPIDFILE
        function finish {
          rm  $EZPIDFILE
        }
        trap finish EXIT
fi

यहाँ इसका उपयोग कैसे करना है। शेबंग के बाद पंक्ति पर ध्यान दें:

     #/bin/bash
     . /opt/racechecker/racechecker
     echo "script are running"
     sleep 120

इसके काम करने का तरीका यह है कि यह मुख्य बैशस्क्रिप्ट फ़ाइल नाम का पता लगाता है और "/ tmp" के तहत एक पीडफाइल बनाता है। यह फिनिश सिग्नल में एक श्रोता को भी जोड़ता है। जब मुख्य स्क्रिप्ट ठीक से खत्म हो जाएगी तो श्रोता पिडफाइल को हटा देगा।

इसके बजाय अगर कोई उदाहरण पेश किए जाने पर पिडफाइल मौजूद होता है, तो दूसरे स्टेटमेंट के अंदर कोड वाले स्टेटमेंट को निष्पादित किया जाएगा। इस मामले में मैंने ऐसा होने पर अलार्म मेल लॉन्च करने का फैसला किया है।

अगर स्क्रिप्ट क्रैश हो जाए तो क्या होगा

दुर्घटनाओं को संभालने के लिए एक और अभ्यास होगा। आदर्श रूप से पीडिफ़ाइल को हटा दिया जाना चाहिए भले ही मुख्य-स्क्रिप्ट किसी भी कारण से दुर्घटनाग्रस्त हो जाए, यह ऊपर मेरे संस्करण में नहीं किया गया है। इसका मतलब है कि यदि स्क्रिप्ट क्रैश हो जाती है तो कार्यक्षमता को पुनर्स्थापित करने के लिए पीडिफ़ाइल को मैन्युअल रूप से निकालना होगा।

सिस्टम क्रैश के मामले में

उदाहरण के लिए / tmp के तहत pidfile / lockfile को संग्रहित करना एक अच्छा विचार है। इस तरह से आपकी स्क्रिप्ट निश्चित रूप से सिस्टम क्रैश के बाद निष्पादित करना जारी रखेगी क्योंकि pidfiles हमेशा बूटअप पर हटा दिया जाएगा।


टिम कैनेडी के एज़्ट्ज के विपरीत, आपकी स्क्रिप्ट में एक दौड़ की स्थिति शामिल है। ऐसा इसलिए है क्योंकि PIDFILE की उपस्थिति और इसके सशर्त निर्माण की जाँच किसी परमाणु ऑपरेशन में नहीं की जाती है।
मैक्सक्लेपजिग

उस पर +1! मैं इस पर विचार करूंगा और अपनी स्क्रिप्ट को संशोधित करूंगा।
जिगस्टैस्टर्ड

-2

मेरी स्क्रिप्ट देखें ...

आप इसे प्यार कर सकते हैं ...।

[rambabu@Server01 ~]$ sh Prevent_cron-OR-Script_against_parallel_run.sh
Parallel RUN Enabled
Now running
Task completed in Parallel RUN...
[rambabu@Server01 ~]$ cat Prevent_cron-OR-Script_against_parallel_run.sh
#!/bin/bash
#Created by RambabuKella
#Date : 12-12-2013

#LOCK file name
Parallel_RUN="yes"
#Parallel_RUN="no"
PS_GREP=0
LOCK=/var/tmp/mylock_`whoami`_"$0"
#Checking for the process
PS_GREP=`ps -ef |grep "sh $0" |grep -v grep|wc -l`
if [ "$Parallel_RUN" == "no" ] ;then
echo "Parallel RUN Disabled"

 if [ -f $LOCK ] || [ $PS_GREP -gt 2   ] ;then
        echo -e "\nJob is already running OR LOCK file exists. "
        echo -e "\nDetail are : "
        ps -ef |grep  "$0" |grep -v grep
        cat "$LOCK"
  exit 6
 fi
echo -e "LOCK file \" $LOCK \" created on : `date +%F-%H-%M` ." &> $LOCK
# do some work
echo "Now running"
echo "Task completed on with single RUN ..."
#done

rm -v $LOCK 2>/dev/null
exit 0
else

echo "Parallel RUN Enabled"

# do some work
echo "Now running"
echo "Task completed in Parallel RUN..."
#done

exit 0
fi
echo "some thing wrong"
exit 2
[rambabu@Server01 ~]$

-3

मैं 'flocktest' नामक एक स्क्रिप्ट में निम्नलिखित समाधान प्रस्तुत करता हूं

#!/bin/bash
export LOGFILE=`basename $0`.logfile
logit () {
echo "$1" >>$LOGFILE
}
PROGPATH=$0
(
flock -x -n 257
(($?)) && logit "'$PROGPATH' is already running!" && exit 0
logit "'$PROGPATH', proc($$): sleeping 30 seconds"
sleep 30
)257<$PROGPATH
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.