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
इससे पहले कि grep
stdin बंद करने के लिए, का अवसर मिल सके 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()
। गैर-जीएनयू सिस्टम को बफ़र्स को निष्क्रिय करने या नियमित रूप से फ्लश करने के लिए कुछ विशेष करना पड़ सकता है।