2009-09-17 23 views
13

मैं एक bash स्क्रिप्ट मैं क्रॉन से हर 5 मिनट चलाने के लिए चाहते हैं ... लेकिन इस बात की संभावना स्क्रिप्ट के पिछले रन तक पूरा नहीं हुआ है ... इस मामले में, मैं सिर्फ बाहर निकलने के लिए नए रन चाहते हैं। मैं सिर्फ एक लॉक फ़ाइल/tmp में भरोसा नहीं करना चाहता हूं .. मैं यह सुनिश्चित करना चाहता हूं कि लॉक फ़ाइल (या जो कुछ भी) का सम्मान करने से पहले प्रक्रिया वास्तव में चल रही है ...मैं कैसे सुनिश्चित कर सकता हूं कि मेरी बैश स्क्रिप्ट पहले से चल रही नहीं है?

मेरे पास यह है अब तक इंटरनेट से चुराया गया है ... मैं इसे थोड़ा सा कैसे कर सकता हूं? या क्या एक बिल्कुल अलग तरीका है जो बेहतर है?

if [ -f /tmp/mylockFile ] ; then 
    echo 'Script is still running' 
else 
    echo 1 > /tmp/mylockFile 
    /* Do some stuff */ 
    rm -f /tmp/mylockFile 
fi 
+0

संभव डुप्लिकेट के लिए त्रुटि संदेश आउटपुट [एक समय में एक शेल स्क्रिप्ट का केवल एक उदाहरण चल रहा है यह सुनिश्चित करने के लिए त्वरित और गंदे तरीके] (http://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only- एक-उदाहरण-ऑफ-ए-शेल-स्क्रिप्ट-चल रहा है-पर) – user

उत्तर

21
# Use a lockfile containing the pid of the running process 
# If script crashes and leaves lockfile around, it will have a different pid so 
# will not prevent script running again. 
# 
lf=/tmp/pidLockFile 
# create empty lock file if none exists 
cat /dev/null >> $lf 
read lastPID < $lf 
# if lastPID is not null and a process with that pid exists , exit 
[ ! -z "$lastPID" -a -d /proc/$lastPID ] && exit 
echo not running 
# save my pid in the lock file 
echo $$ > $lf 
# sleep just to make testing easier 
sleep 5 

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

+1

'$ lf' स्पर्श करने के बजाय' cat/dev/null >> $ lf' क्यों? कोई लूप नहीं होने पर 'नींद' क्यों? –

+0

'स्पर्श (1) 'भी अच्छा है। नींद सिर्फ प्रदर्शन के लिए है, मेरी स्क्रिप्ट खंड स्वयं को टेस्ट करने योग्य बनाने के लिए है। – DigitalRoss

+1

(यानी, उस स्क्रिप्ट के समाप्त होने पर ही पिड गायब हो जाएगा) – DigitalRoss

4

आप इस प्रक्रिया के अस्तित्व की जांच करना चाहते हैं, तो बस अगर यह वहाँ

ps aux | grep your_script_name

के उत्पादन को देखो, यह मृत नहीं है ...

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

+1

इसके अतिरिक्त, आप उस लॉक फ़ाइल में वर्तमान BASH प्रक्रिया के पीआईडी ​​को स्टोर कर सकते हैं। BASH एक चर '$$' प्रदान करता है (उद्धरण घटाएं) जो उस नंबर को देता है। यहां देखें: http://tldp.org/LDP/abs/html/internalvariables।उन चर के लिए एचटीएमएल – Buggabill

+0

-1 क्या होगा यदि "emacs your_script_name" चल रही प्रक्रियाओं में से एक है? – mob

+0

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

4

स्टोर mylockFile में अपने पीआईडी। जब आपको जांच करने की आवश्यकता होती है, तो फ़ाइल से पढ़ने वाले पिड के साथ प्रक्रिया के लिए पीएस देखें। यदि यह मौजूद है, तो आपकी स्क्रिप्ट चल रही है।

0

तुम हमेशा सिर्फ कर सकते हैं:

if ps -e -o cmd | grep scriptname > /dev/null; then 
    exit 
fi 

लेकिन मैं lockfile अपने आप की तरह है, तो मैं ताला फ़ाइल के बिना यह कर नहीं होगा और साथ ही।

+1

इस पर निर्भर करता है कि पोर्टेबल को यह कैसे होना चाहिए, आपको अपने पीएस विकल्पों को ट्विक करने की आवश्यकता हो सकती है, और आप/dev/null –

+2

के बजाय grep को जोड़ने में सक्षम हो सकते हैं सह-कार्यकर्ता पर्याप्त नहीं है: कोई भी " कम स्क्रिप्टनाम "और यह स्क्रिप्ट को – mob

+0

चलने से रोकने के लिए पर्याप्त होगा: हां, कभी इसके बारे में सोचा नहीं, सिर्फ इसलिए कि मैं इसे कभी नहीं करता ;-) लॉकफ़ाइल बेहतर है। –

9

आप शायद मैन पेज पर एक नज़र डालना चाहते हैं flock कमांड, यदि आप अपने वितरण पर इसे पाने के लिए भाग्यशाली हैं।

 
NAME 
     flock - Manage locks from shell scripts 
SYNOPSIS 
     flock [-sxon] [-w timeout] lockfile [-c] command... 
+0

यह समाधान कुछ अन्य सुझाए गए समाधानों के विपरीत, सबसे साफ रूप से जांच और लॉक प्राप्त करने के बीच दौड़ की स्थिति से बचाता है। यदि आपके पास 'झुंड (1)' है (जो डेबियन/उबंटू आदि में उपयोग-लिनक्स के साथ आता है) निश्चित रूप से इसका उपयोग करें। ओपी उपयोग के मामले के लिए, आपको एक छोटी टाइमआउट की आवश्यकता है (उदा। -w 1)। यदि आदेश पहले से चल रहा है, तो झुंड 1 सेकंड के बाद छोड़ देगा, और कमांड नहीं चलाएगा, अन्यथा, यह लॉक प्राप्त करेगा और कमांड शुरू करेगा। – arielf

+0

समय-समय पर '-w 1' का उपयोग करने और 1 सेकंड के बाद बाहर निकलने के बजाय, ओपी' -n, --nb, --nonblock विफलता (1 के बाहर निकलने के कोड के साथ) का उपयोग करने के बजाय, लॉक तुरंत नहीं हो सकता है अधिग्रहण किया। 'मेरे उत्तर में उदाहरण देखें जो इस विषय के सक्रिय होने के बाद दुखद तरीके से जोड़ा गया था। – mattst

1

कुछ मामलों में, आप जो स्क्रिप्ट चल रही है के बीच भेद और कुछ संगामिति लेकिन सभी नहीं अनुमति देने के लिए सक्षम होने के लिए चाहते हो सकता है। उस स्थिति में, आप प्रति-उपयोगकर्ता, प्रति-टीटी या क्रॉन-विशिष्ट ताले का उपयोग कर सकते हैं।

आप इस तरह के $ उपयोगकर्ता या एक तरह के रूप में tty कार्यक्रम फ़ाइल नाम बनाने के लिए की उपज के तौर वातावरण चरों का उपयोग कर सकते हैं। cron के लिए, आप crontab फ़ाइल में एक चर सेट कर सकते हैं और अपनी स्क्रिप्ट में इसके लिए परीक्षण कर सकते हैं।

6

एक ताला फ़ाइल का उपयोग कभी नहीं हमेशा एक ताला निर्देशिका का उपयोग करें। आपके विशिष्ट मामले में, यह इतना महत्वपूर्ण नहीं है क्योंकि स्क्रिप्ट की शुरुआत 5min अंतराल में निर्धारित है। लेकिन यदि आपने कभी भी वेबसर्वर सीजीआई-स्क्रिप्ट के लिए इस कोड का पुन: उपयोग किया है तो आप टोस्ट हैं।

if mkdir /tmp/my_lock_dir 2>/dev/null 
then 
    echo "running now the script" 
    sleep 10 
    rmdir /tmp/my_lock_dir 
fi 

यदि आपके पास स्टेल लॉक है तो इसका कोई समस्या है, इसका मतलब है कि लॉक है लेकिन कोई संबंधित प्रक्रिया नहीं है। आपका क्रॉन कभी नहीं चलेगा।

निर्देशिका का उपयोग क्यों करें? क्योंकि mkdir एक परमाणु ऑपरेशन है। एक समय में केवल एक ही प्रक्रिया एक निर्देशिका बना सकती है, अन्य सभी प्रक्रियाओं में त्रुटि होती है। यह साझा फाइल सिस्टम और शायद विभिन्न ओएस प्रकारों के बीच भी काम करता है।

+0

लॉक फ़ाइलें एनएफएस में काम नहीं करती हैं - जो साझा होस्टिंग में आम है। हम अक्सर उसी कारण से लॉक निर्देशिका का उपयोग करते हैं। –

3

आप एक lockfile का उपयोग करते हैं, तो आप यह सुनिश्चित करें कि lockfile हमेशा निकाल दिया जाता है बनाना चाहिए। आप 'जाल' के साथ ऐसा कर सकते हैं:

if (set -o noclobber; echo "locked" > "$lockfile") 2> /dev/null; then 
    trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT 
    echo "Locking succeeded" >&2 
    rm -f "$lockfile" 
else 
    echo "Lock failed - exit" >&2 
    exit 1 
fi 

noclobber विकल्प के लिए एक निर्देशिका का उपयोग कर की तरह, lockfile परमाणु के निर्माण में आता है।

0

आप उपयोग कर सकते हैं यह एक:

pgrep -f "/bin/\w*sh .*scriptname" | grep -vq $$ && exit 
3

एक एक लाइनर के रूप में है और आप एक lockfile (जैसे बी/सी, केवल पढ़ने के फाइल सिस्टम, आदि के /)

test "$(pidof -x $(basename $0))" != $$ && exit 
का उपयोग नहीं करना चाहते हैं, तो

यह जांचता है कि आपकी लिपि का नाम रखने वाली पीआईडी ​​की पूरी सूची वर्तमान पीआईडी ​​के बराबर है। "-x" शैल स्क्रिप्ट के नाम के लिए भी जांच करता है।

बैश यह भी कम करता है और तेजी से:

[[ "$(pidof -x $(basename $0))" != $$ ]] && exit 
1

मैं आज इस समस्या को हल करने की कोशिश कर रहा था और मैं नीचे के साथ आया था:

COMMAND_LINE="$0 $*" 
JOBS=$(SUBSHELL_PID=$BASHPID; ps axo pid,command | grep "${COMMAND_LINE}" | grep -v $$ | g rep -v ${SUBSHELL_PID} | grep -v grep) 
if [[ -z "${JOBS}" ]] 
then 
    # not already running 
else 
    # already running 
fi 

$BASHPID पर यह निर्भर करता है जो पीआईडी ​​शामिल सबहेल के अंदर ($$ सबहेल में पैरेंट पिड है)। हालांकि, यह बैश v4 पर निर्भर करता है और मुझे इसे ओएसएक्स पर चलाने की आवश्यकता है जिसमें बैश v3.2.48 है। मैं अंत में एक और समाधान के साथ आया था और यह है क्लीनर:

JOBS=$(sh -c "ps axo pid,command | grep \"${COMMAND_LINE}\" | grep -v grep | grep -v $$") 
0

के बाद से एक सॉकेट समाधान अभी तक का उल्लेख नहीं किया गया है यह उनका कहना है कि सॉकेट प्रभावी mutexes के रूप में इस्तेमाल किया जा सकता लायक है। सॉकेट निर्माण एक परमाणु ऑपरेशन है, जैसे mkdir गनस्टिक ने इंगित किया है, इसलिए एक सॉकेट लॉक या म्यूटेक्स के रूप में उपयोग करने के लिए उपयुक्त है।

टिम Kay के पर्ल स्क्रिप्ट 'सोलो' यकीन है कि केवल एक स्क्रिप्ट की एक प्रति किसी एक समय में चलाया जा सकता है बनाने के लिए एक बहुत छोटा और प्रभावी स्क्रिप्ट है। यह विशेष रूप से क्रॉन नौकरियों के उपयोग के लिए डिज़ाइन किया गया था, हालांकि यह अन्य कार्यों के लिए भी पूरी तरह से काम करता है और मैंने इसे गैर-क्रोब नौकरियों के लिए बहुत प्रभावी ढंग से उपयोग किया है।

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

*/5 * * * * solo -port=3801 /path/to/script.sh args args args 

# "/path/to/script.sh args args args" is only called if no other instance of 
# "/path/to/script.sh" is running, or more accurately if the socket on port 3801 
# is not open. Distinct port numbers can be used for different programs so that 
# if script_1.sh is running it does not prevent script_2.sh from starting, I've 
# used the port range 3801 to 3810 without conflicts. For Linux non-root users 
# the valid port range is 1024 to 65535 (0 to 1023 are reserved for root). 

* * * * * solo -port=3802 /path/to/script_1.sh 
* * * * * solo -port=3803 /path/to/script_2.sh 

# Flock can also be used in cron jobs with a distinct lock path for different 
# programs, in the example below script_3.sh will only be started if the one 
# started a minute earlier has already finished. 

* * * * * flock -n /tmp/path.to.lock -c /path/to/script_3.sh 

लिंक::

आशा

यहाँ कैसे आप इसे क्रॉन साथ उपयोग कर सकते हैं का एक उदाहरण है इससे मदद मिलती है।

0

आप this का उपयोग कर सकते हैं।

मैं सिर्फ समाधान को कॉपी-पेस्ट कर दूंगा, क्योंकि यह दोनों प्रश्नों का उत्तर है (मैं तर्क दूंगा कि यह वास्तव में इस प्रश्न के लिए बेहतर फिट है)।

प्रयोग

  1. शामिल sh_lock_functions.sh
  2. init का उपयोग कर sh_lock_init
  3. ताला का उपयोग कर sh_acquire_lock
  4. जांच ताला sh_check_lock का उपयोग कर
  5. संयुक्त राष्ट्र sh_remove_lock का उपयोग कर ताला

स्क्रिप्ट फ़ाइल

sh_lock_functions.sh

#!/bin/bash 

function sh_lock_init { 
    sh_lock_scriptName=$(basename $0) 
    sh_lock_dir="/tmp/${sh_lock_scriptName}.lock" #lock directory 
    sh_lock_file="${sh_lock_dir}/lockPid.txt" #lock file 
} 

function sh_acquire_lock { 
    if mkdir $sh_lock_dir 2>/dev/null; then #check for lock 
     echo "$sh_lock_scriptName lock acquired successfully.">&2 
     touch $sh_lock_file 
     echo $$ > $sh_lock_file # set current pid in lockFile 
     return 0 
    else 
     touch $sh_lock_file 
     read sh_lock_lastPID < $sh_lock_file 
     if [ ! -z "$sh_lock_lastPID" -a -d /proc/$sh_lock_lastPID ]; then # if lastPID is not null and a process with that pid exists 
      echo "$sh_lock_scriptName is already running.">&2 
      return 1 
     else 
      echo "$sh_lock_scriptName stopped during execution, reacquiring lock.">&2 
      echo $$ > $sh_lock_file # set current pid in lockFile 
      return 2 
     fi 
    fi 
    return 0 
} 

function sh_check_lock { 
    [[ ! -f $sh_lock_file ]] && echo "$sh_lock_scriptName lock file removed.">&2 && return 1 
    read sh_lock_lastPID < $sh_lock_file 
    [[ $sh_lock_lastPID -ne $$ ]] && echo "$sh_lock_scriptName lock file pid has changed.">&2 && return 2 
    echo "$sh_lock_scriptName lock still in place.">&2 
    return 0 
} 

function sh_remove_lock { 
    rm -r $sh_lock_dir 
} 

प्रयोग उदाहरण

sh_lock_usage_example.sh

#!/bin/bash 
. /path/to/sh_lock_functions.sh # load sh lock functions 

sh_lock_init || exit $? 

sh_acquire_lock 
lockStatus=$? 
[[ $lockStatus -eq 1 ]] && exit $lockStatus 
[[ $lockStatus -eq 2 ]] && echo "lock is set, do some resume from crash procedures"; 

#monitoring example 
cnt=0 
while sh_check_lock # loop while lock is in place 
do 
    echo "$sh_scriptName running (pid $$)" 
    sleep 1 
    let cnt++ 
    [[ $cnt -gt 5 ]] && break 
done 

#remove lock when process finished 
sh_remove_lock || exit $? 

exit 0 

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

 संबंधित मुद्दे