tailबाहर निकलने के लिए कुछ तरीके हैं :
खराब दृष्टिकोण: tailएक और पंक्ति लिखने के लिए बाध्य करना
आप एक मिलान और बाहर निकलने के tailतुरंत बाद आउटपुट की एक और पंक्ति लिखने के लिए बाध्य कर सकते हैं grep। यह tailएक प्राप्त करने का कारण होगा SIGPIPE, जिससे यह बाहर निकल जाएगा। ऐसा करने का एक तरीका यह है कि बाहर निकलने के tailबाद निगरानी की जा रही फ़ाइल को संशोधित करें grep।
यहाँ कुछ उदाहरण कोड है:
tail -f logfile.log | grep -m 1 "Server Started" | { cat; echo >>logfile.log; }
इस उदाहरण में, catतब तक बाहर नहीं निकलेंगे, जब तक grepअपना स्टडआउट बंद नहीं कर दिया tailजाता , इसलिए पाइप को लिखने में सक्षम होने की संभावना नहीं है , इससे पहले grepकि इसकी स्टड को बंद करने का मौका मिला हो। catका उपयोग अनमॉडिफाइड के मानक उत्पादन को फैलाने के लिए किया जाता है grep।
यह दृष्टिकोण अपेक्षाकृत सरल है, लेकिन कई डाउनसाइड हैं:
- यदि
grepस्टड बंद करने से पहले स्टडआउट बंद हो जाता है, तो हमेशा एक दौड़ की स्थिति होगी: grepस्टडआउट को बंद कर देता है, ट्रिगर catकरने के लिए बाहर निकलता है, ट्रिगर करता है echo, tailएक लाइन को आउटपुट करने के लिए ट्रिगर करता है। इस लाइन के लिए भेजा जाता है, तो grepइससे पहले कि grepstdin बंद करने के लिए, का अवसर मिल सके tailनहीं मिलेगा SIGPIPEजब तक यह एक और लाइन लिखता है।
- इसके लिए लॉग फ़ाइल में लिखने की पहुँच आवश्यक है।
- आपको लॉग फ़ाइल को संशोधित करने के साथ ठीक होना चाहिए।
- यदि आप किसी अन्य प्रक्रिया के रूप में एक ही समय में लिखने के लिए होते हैं (लॉग्स बीच में हो सकता है, जिससे लॉगलाइन संदेश के बीच में एक नई पंक्ति दिखाई दे) तो आप लॉग फ़ाइल को दूषित कर सकते हैं।
- यह दृष्टिकोण विशिष्ट है-
tailयह अन्य कार्यक्रमों के साथ काम नहीं करेगा।
- तीसरा पाइपलाइन चरण दूसरी पाइपलाइन चरण के रिटर्न कोड तक पहुंचना मुश्किल बनाता है (जब तक कि आप पॉसिक्स एक्सटेंशन जैसे कि
bash'एस PIPESTATUSएरे ' का उपयोग नहीं कर रहे हों )। इस मामले में यह कोई बड़ी बात नहीं है क्योंकि grepहमेशा 0 वापस आ जाएगा, लेकिन सामान्य तौर पर मध्य चरण को एक अलग कमांड से बदला जा सकता है जिसका रिटर्न कोड आप परवाह करते हैं (जैसे, कुछ ऐसा जो 0 तब वापस आता है जब "सर्वर शुरू" का पता चलता है, 1 जब "सर्वर शुरू करने में विफल रहा है" का पता चला है)।
अगले दृष्टिकोण इन सीमाओं से बचते हैं।
एक बेहतर दृष्टिकोण: पाइपलाइनों से बचें
आप पाइपलाइन से बचने के लिए पूरी तरह से एक एफआईएफओ का उपयोग कर सकते हैं, जिससे निष्पादन एक बार grepरिटर्न जारी रखने की अनुमति देता है। उदाहरण के लिए:
fifo=/tmp/tmpfifo.$$
mkfifo "${fifo}" || exit 1
tail -f logfile.log >${fifo} &
tailpid=$! # optional
grep -m 1 "Server Started" "${fifo}"
kill "${tailpid}" # optional
rm "${fifo}"
टिप्पणी के साथ चिह्नित लाइनों को # optionalहटाया जा सकता है और कार्यक्रम अभी भी काम करेगा; tailजब तक यह इनपुट की एक और लाइन पढ़ता है या किसी अन्य प्रक्रिया से मारा जाता है, तब तक सिर्फ भटकता रहेगा।
इस दृष्टिकोण के फायदे हैं:
- आपको लॉग फ़ाइल को संशोधित करने की आवश्यकता नहीं है
- दृष्टिकोण इसके अलावा अन्य उपयोगिताओं के लिए काम करता है
tail
- यह एक दौड़ की स्थिति से ग्रस्त नहीं है
- आप आसानी से
grep(या जो भी वैकल्पिक आदेश आप उपयोग कर रहे हैं) का रिटर्न मान प्राप्त कर सकते हैं
इस दृष्टिकोण के लिए नकारात्मकता जटिलता है, विशेष रूप से फीफो का प्रबंधन: आपको सुरक्षित रूप से एक अस्थायी फ़ाइल नाम उत्पन्न करने की आवश्यकता होगी, और आपको यह सुनिश्चित करने की आवश्यकता होगी कि उपयोगकर्ता के बीच में Ctrl-C हिट होने पर भी अस्थायी FIFO हटा दिया जाए। लिपी। यह एक जाल का उपयोग करके किया जा सकता है।
वैकल्पिक दृष्टिकोण: मारने के लिए एक संदेश भेजें tail
आप tailइसे सिग्नल भेजकर बाहर निकलने के लिए पाइपलाइन चरण प्राप्त कर सकते हैं SIGTERM। चुनौती मज़बूती से कोड में एक ही जगह दो चीजों को जान रही है: tailपीआईडी और क्या grepबाहर निकल गई है।
जैसे पाइपलाइन के साथ tail -f ... | grep ..., tailपृष्ठभूमि tailऔर पठन द्वारा एक चर में पीआईडी को बचाने के लिए पहले पाइपलाइन चरण को संशोधित करना आसान है $!। यह भी चलाने के लिए दूसरी पाइपलाइन चरण संशोधित करने के लिए आसान है killजब grepबाहर निकलता है। समस्या यह है कि पाइपलाइन के दो चरण अलग-अलग "निष्पादन वातावरण" (POSIX मानक की शब्दावली में) चलते हैं, इसलिए दूसरी पाइपलाइन चरण पहले पाइपलाइन चरण द्वारा निर्धारित किसी भी चर को नहीं पढ़ सकता है। शेल चर का उपयोग किए बिना, या तो दूसरे चरण में किसी भी तरह से tailपीआईडी का पता लगाना चाहिए ताकि रिटर्न tailकरते समय वह मार सके grepया रिटर्न करते समय पहले चरण को किसी तरह अधिसूचित किया जाए grep।
दूसरा चरण पीआईडी pgrepप्राप्त करने के लिए उपयोग कर सकता है tail, लेकिन यह अविश्वसनीय होगा (आप गलत प्रक्रिया से मेल खा सकते हैं) और गैर-पोर्टेबल ( pgrepपोसिक्स मानक द्वारा निर्दिष्ट नहीं है)।
पहला चरण पीआईडी को पाइप के माध्यम से पीआईडी को दूसरे चरण में भेज सकता है echo, लेकिन यह स्ट्रिंग tailआउटपुट के साथ मिश्रित हो जाएगी । इन दोनों के परिणाम के आधार पर, एक जटिल एस्केलिंग योजना की आवश्यकता हो सकती है tail।
जब आप grepबाहर निकलते हैं तो पहले पाइपलाइन चरण को सूचित करने के लिए आप दूसरी पाइपलाइन चरण का उपयोग कर सकते हैं । फिर पहला चरण मार सकता है tail। यहाँ कुछ उदाहरण कोड है:
fifo=/tmp/notifyfifo.$$
mkfifo "${fifo}" || exit 1
{
# run tail in the background so that the shell can
# kill tail when notified that grep has exited
tail -f logfile.log &
# remember tail's PID
tailpid=$!
# wait for notification that grep has exited
read foo <${fifo}
# grep has exited, time to go
kill "${tailpid}"
} | {
grep -m 1 "Server Started"
# notify the first pipeline stage that grep is done
echo >${fifo}
}
# clean up
rm "${fifo}"
इस दृष्टिकोण में पिछले दृष्टिकोण के सभी पक्ष और विपक्ष हैं, सिवाय इसके कि यह अधिक जटिल है।
बफरिंग के बारे में चेतावनी
POSIX स्टड और स्टडआउट स्ट्रीम को पूरी तरह से बफ़र करने की अनुमति देता है, जिसका अर्थ है कि tailआउटपुट को grepमनमाने ढंग से लंबे समय तक संसाधित नहीं किया जा सकता है । जीएनयू सिस्टम पर कोई समस्या नहीं होनी चाहिए: जीएनयू grepउपयोग करता है read(), जो सभी बफरिंग से बचा जाता है, और जीएनयू स्टडआउट को लिखते समय tail -fनियमित कॉल करता है fflush()। गैर-जीएनयू सिस्टम को बफ़र्स को निष्क्रिय करने या नियमित रूप से फ्लश करने के लिए कुछ विशेष करना पड़ सकता है।