मैं शेल स्क्रिप्ट में किसी फ़ाइल की प्रतीक्षा कैसे करूं?


15

मैं एक शेल स्क्रिप्ट लिखने की कोशिश कर रहा हूं, जिसे एक फाइल के लिए /tmpनिर्देशिका में प्रदर्शित होने का इंतजार करना पड़ेगा sleep.txtऔर एक बार जब यह मिल जाएगा तो कार्यक्रम बंद हो जाएगा, अन्यथा मैं चाहता हूं कि कार्यक्रम नींद में (निलंबित) स्थिति में रहे जब तक कि फ़ाइल स्थित न हो। । अब, मैं मान रहा हूं कि मैं एक परीक्षण कमांड का उपयोग करूंगा। तो, कुछ इस तरह

(if [ -f "/tmp/sleep.txt" ]; 
then stop 
   else sleep.)

मैं शेल स्क्रिप्ट लिखने के लिए बिल्कुल नया हूं और किसी भी मदद की बहुत सराहना की जाती है!


को देखो $MAILPATH
mikeserv

जवाबों:


24

लिनक्स के अंतर्गत, आप उपयोग कर सकते हैं inotify गिरी सबसिस्टम को कुशलता से एक निर्देशिका में एक फ़ाइल की उपस्थिति के लिए इंतजार:

while read i; do if [ "$i" = sleep.txt ]; then break; fi; done \
   < <(inotifywait  -e create,open --format '%f' --quiet /tmp --monitor)
# script execution continues ...

( <()आउटपुट रीडायरेक्शन सिंटैक्स के लिए बैश मानकर )

निश्चित समय अंतराल मतदान की तुलना में इस दृष्टिकोण का लाभ

while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# script execution continues ...

यह है कि कर्नेल अधिक सोता है। create,openजब कोई फ़ाइल /tmpबनाई जाती है या खोली जाती है , तो स्क्रिप्ट की तरह एक inotify इवेंट विनिर्देश स्क्रिप्ट के निष्पादन के लिए निर्धारित होता है । निश्चित समय अंतराल के मतदान के साथ आप हर बार वेतन वृद्धि के लिए सीपीयू साइकिल बर्बाद करते हैं।

जब फ़ाइल पहले से मौजूद है, तो मैंने openपंजीकरण करने के लिए घटना को भी शामिल किया touch /tmp/sleep.txt


धन्यवाद, यह कमाल है! यदि आपको फ़ाइल का नाम पता है तो आपको लूप की आवश्यकता क्यों है? ऐसा क्यों नहीं किया गया inotifywait -e create,open --format '%f' --quiet /tmp/sleep.txt --monitor > /dev/null ; # continues once /tmp/sleep.txt is created/opened?
NHDaly

ओह, जे.के. उपकरण स्थापित करने के बाद अब मुझे समझ में आया। inotifywaitअपने आप में एक लूप है, और यह फ़ाइल खोले जाने / निर्मित होने पर हर बार एक लाइन आउटपुट करता है। तो जब आप बदल जाते हैं तो आपको लूप को तोड़ने की आवश्यकता होती है।
NHDaly

सिवाय इसके कि यह एक दौड़ की स्थिति पैदा करता है - टेस्ट -ई / स्लीप संस्करण के विपरीत। यह गारंटी देने का कोई तरीका नहीं है कि लूप दर्ज किए जाने से ठीक पहले फ़ाइल नहीं बनाई जाएगी - जिस स्थिति में ईवेंट छूट जाएगा। आपको लूप से पहले (स्लीप 1; [[-e /tmp/sleep.txt]] && टच /tmp/sleep.txt;) और कुछ जोड़ना होगा। वास्तविक व्यापार तर्क के आधार पर निश्चित रूप से कौन से मुद्दे सड़क पर पैदा हो सकते हैं
n-अलेक्जेंडर

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

@ maxschlepzig इसके विपरीत। जब तक आदेश लागू नहीं किया जाता है, तब तक यह नहीं माना जा सकता है। मूल बातें।
n-अलेक्जेंडर

10

बस अपने परीक्षण को whileलूप में रखें:

while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# next command

तो जैसा कि आपने लिखा है, यह तर्क है: जबकि फ़ाइल मौजूद नहीं है, स्क्रिप्ट सो जाएगी। अन्यथा, यह किया जाता है। सही बात?
मो गेंज

@MoGainz सही। sleepप्रत्येक पुनरावृत्ति में प्रतीक्षा करने के लिए संख्या के बाद की संख्या है - आप अपनी आवश्यकताओं के आधार पर इसे बदल सकते हैं।
जिमीज

7

inotifywaitअब तक दिए गए कुछ- आधारित दृष्टिकोणों के साथ कुछ समस्याएं हैं:

  • वे एक sleep.txtफ़ाइल खोजने में विफल रहते हैं जिसे पहले अस्थायी नाम के रूप में बनाया गया है और फिर नाम बदल दिया गया है sleep.txt। एक के moved_toअलावा घटनाओं के लिए मैच की जरूरत हैcreate
  • फाइल के नाम में न्यूलाइन कैरेक्टर हो सकते हैं, न्यूलाइन सीमांकित फाइलों के नाम प्रिंट करना यह निर्धारित करने के लिए पर्याप्त नहीं है कि क्या sleep.txtबनाया गया है। क्या होगा अगर एक foo\nsleep.txt\nbarफ़ाइल उदाहरण के लिए बनाई गई है?
  • क्या होगा यदि फ़ाइल शुरू होने से पहले बनाई गई है inotifywaitऔर घड़ी स्थापित की गई है? फिर inotifywaitपहले से ही यहां मौजूद एक फाइल के लिए हमेशा के लिए इंतजार करना होगा। आपको यह सुनिश्चित करने की आवश्यकता होगी कि घड़ी स्थापित होने के बाद फ़ाइल पहले से ही वहां नहीं है।
  • कुछ समाधान inotifywaitचल रहे हैं (कम से कम जब तक एक और फ़ाइल नहीं बनाई जाती है) फ़ाइल मिलने के बाद।

उन लोगों को संबोधित करने के लिए, आप कर सकते हैं:

sh -c 'echo "$$" &&
        LC_ALL=C exec inotifywait -me create,moved_to --format=/%f/ . 2>&1' | {
  IFS= read pid &&
    while IFS= read -r line && [ "$line" != "Watches established." ]; do
      : wait for watches to be established
    done
  [ -e sleep.txt ] || [ -L sleep.txt ] || grep -qxF /sleep.txt/ && kill "$pid"
}

ध्यान दें कि हम sleep.txtवर्तमान निर्देशिका में निर्माण के लिए देख रहे हैं , .(इसलिए आप cd /tmp || exitअपने उदाहरण से पहले ऐसा करेंगे )। वर्तमान निर्देशिका कभी नहीं बदलती है, इसलिए जब वह पाइप लाइन सफलतापूर्वक लौटती है, तो यह sleep.txtवर्तमान निर्देशिका में है जो बनाई गई है।

बेशक, आप बदल सकते हैं .के साथ /tmpऊपर है, लेकिन, जबकि inotifywaitचल रहा है, /tmpकई बार नाम बदला जा सकता था (के लिए की संभावना नहीं /tmpहै, लेकिन सामान्य मामले में विचार करने के लिए कुछ) या एक नया फाइल सिस्टम उस पर घुड़सवार, इसलिए जब पाइप लाइन रिटर्न, यह नहीं हो सकता एक है /tmp/sleep.txtकि बनाया गया है, लेकिन /new-name-for-the-original-tmp/sleep.txtइसके बजाय। /tmpअंतराल में एक नई निर्देशिका भी बनाई जा सकती थी और उस पर किसी की नजर नहीं जाती थी, इसलिए sleep.txtबनाए गए का पता नहीं चलता।


1

स्वीकृत उत्तर वास्तव में काम करता है (धन्यवाद maxschlepzig) लेकिन आपकी स्क्रिप्ट से बाहर निकलने तक पृष्ठभूमि में inotifywait निगरानी छोड़ देता है। एकमात्र उत्तर जो आपकी आवश्यकताओं से मेल खाता है (यानी अंदर / tmp को दिखाने के लिए sleep.txt का इंतजार) स्टीफन का प्रतीत होता है, अगर inotifywait द्वारा निगरानी की जाने वाली निर्देशिका को डॉट (।) से बदलकर '/ tmp' कर दिया जाता है।

हालाँकि, यदि आप केवल अपने स्लीप.टेक् स फ्लैग को लगाने के लिए एक अस्थायी डायरेक्टरी का उपयोग करने के लिए तैयार हैं और यह शर्त लगा सकते हैं कि कोई और उस डायरेक्टरी में कोई फाइल नहीं डालेगा, तो बस इनओटीफाइवाइट से इस डायरेक्टरी को देखने के लिए कहें कि फाइल क्रिएशन के लिए पर्याप्त होगा:

पहला चरण: वह निर्देशिका बनाएँ जिसे आप मॉनिटर करेंगे:

directoryToPutSleepFile=$(mktemp -d)

दूसरा चरण: सुनिश्चित करें कि निर्देशिका वास्तव में है

until [ -d $directoryToPutSleepFile ]; do sleep 0.1; done

तीसरा चरण: तब तक प्रतीक्षा करें जब तक कोई फ़ाइल अंदर दिखाई न दे $directoryToPutSleepFile

inotifywait -e create --format '%f' --quiet $directoryToPutSleepFile

आपके द्वारा डाली गई फ़ाइल का $directoryToPutSleepFileनाम sleep.txt awake.txt रखा जा सकता है, जो भी हो। जिस क्षण आपकी स्क्रिप्ट के अंदर कोई फ़ाइल बनाई जाती है $directoryToPutSleepFileवह inotifywaitकथन को जारी रखेगी ।


1
लेकिन यह फ़ाइल के निर्माण को याद कर सकता है, अगर एक और बस पहले बनाया गया था, जिससे sleep.txtदो इनबॉइस्वाइट इनवोकेशन को इनबेटइन बनाया जा सके।
स्टीफन चेज़लस

इसे संबोधित करने के लिए वैकल्पिक तरीके के लिए मेरा जवाब देखें ।
स्टीफन चेजलस 15

कृपया मेरे कोड का प्रयास करें। inotifywait केवल एक बार मंगवाया गया है। जब sleep.txt बनाया जाता है (या पहले से ही वहां लिखा / पढ़ा जाता है), तो "sleep.txt" आउटपुट उत्पन्न करता है और 'किए गए' कथन के बाद निष्पादन जारी रहता है।
निकोलास

जब तक कोई फ़ाइल sleep.txtबनाई जाती है, तब तक इसे कई बार लागू किया जाता है। उदाहरण के लिए प्रयास करें touch /tmp/foo /tmp/sleep.txt, फिर एक उदाहरण inotifywaitरिपोर्ट करेगा fooऔर बाहर निकलेगा, और जब तक अगला inotifywait शुरू हो जाता है, तब तक sleep.txt लंबे समय तक हो चुका होगा इसलिए inotifywait इसके निर्माण का पता नहीं लगाएगा।
स्टीफन चेज़लस

आप कई इनवोकेशन के बारे में सही थे: / tmp के तहत बनाई गई हर फ़ाइल के लिए एक मंगलाचरण। मैंने अपना उत्तर अपडेट कर दिया। आपके कमेंट के लिए धन्यवाद।
निकोलास

0

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

#!/bin/bash
while [[ ! -e /tmp/file ]] ; do
    sleep 1
done

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



0

Maxschlepzig के स्वीकृत उत्तर के आधार पर (और /superuser/270529/monitoring-a-file-until-a-string-is-found/ पर स्वीकृत उत्तर से एक विचार ) मैं निम्नलिखित सुधार का प्रस्ताव करता हूं ( मेरे विचार में) उत्तर जो टाइमआउट के साथ भी काम कर सकता है:

# Enable pipefail, so if the left side of the pipe fails it does not get silently ignored
set -o pipefail
( timeout 120 inotifywait -e create,open --format '%f' --quiet /tmp --monitor & ) | while read i; do if [ "$i" == 'sleep.txt' ]; then break; fi; done
EXIT_STATUS=$?
if [ "${EXIT_STATUS}" == '124' ]; then
  echo "Timeout happened"
fi

यदि फ़ाइल दिए गए समय के भीतर बनाई / खोली नहीं जाती है, तो बाहर निकलने की स्थिति 124 है (जैसा कि टाइमआउट प्रलेखन (मैन पेज))। यदि यह निर्मित / खोला जाता है, तो बाहर निकलने की स्थिति 0 (सफलता) है।

हाँ, inotifywait एक सब-शेल में इस तरह से चलता है और यह सब-शेल केवल तभी समाप्त होता है जब टाइमआउट होता है या जब मुख्य स्क्रिप्ट बाहर निकलती है (जो भी पहले आती है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.