जवाबों:
$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log
यह काम किस प्रकार करता है:
cat
नामक फ़ाइल को पढ़ता है input.log
और इसे अपने मानक आउटपुट स्ट्रीम में प्रिंट करता है।
आम तौर पर मानक आउटपुट एक टर्मिनल से जुड़ा होता है, लेकिन इस छोटी स्क्रिप्ट में |
ऐसा शेल होता है cat
जो मानक इनपुट के मानक आउटपुट को पुनर्निर्देशित करता है sed
।
sed
डेटा पढ़ता है (जैसा कि cat
यह उत्पादन करता है), इसे संसाधित करता है ( -e
विकल्प के साथ प्रदान की गई स्क्रिप्ट के अनुसार ) और फिर इसे अपने मानक आउटपुट पर प्रिंट करता है। स्क्रिप्ट का "s/^/$(date -R) /"
अर्थ है date -R
कमांड द्वारा उत्पन्न पाठ के लिए लाइन की हर शुरुआत को बदलें (कमांड के लिए सामान्य निर्माण है:) s/pattern/replace/
।
फिर एक फ़ाइल >>
bash
के आउटपुट को पुनर्निर्देशित किया sed
जाता है जिसे कहा जाता है output.log
( >
मतलब फ़ाइल सामग्री को प्रतिस्थापित करता है और >>
इसका अर्थ है अंत में जोड़ें)।
समस्या का $(date -R)
मूल्यांकन एक बार जब आप स्क्रिप्ट चलाते हैं तो यह प्रत्येक लाइन की शुरुआत में वर्तमान टाइमस्टैम्प डालेगी। वर्तमान टाइमस्टैम्प एक संदेश उत्पन्न होने के क्षण से बहुत दूर हो सकता है। इससे बचने के लिए आपको संदेशों को संसाधित करना होगा क्योंकि वे फ़ाइल में लिखे गए हैं, क्रॉन जॉब के साथ नहीं।
ऊपर वर्णित मानक धारा पुनर्निर्देशन को पाइप कहा जाता है । आप इसे न केवल |
स्क्रिप्ट में आदेशों के बीच, बल्कि एक FIFO फ़ाइल (उर्फ नामित पाइप ) के माध्यम से पुनर्निर्देशित कर सकते हैं । एक प्रोग्राम फ़ाइल को लिखेगा और दूसरा डेटा पढ़ेगा और इसे पहले भेजे गए अनुसार प्राप्त करेगा।
एक उदाहरण चुनें:
$ mkfifo foo.log.fifo
$ while true; do cat foo.log.fifo | sed -e "s/^/$(date -R) /" >> foo.log; done;
# have to open a second terminal at this point
$ echo "foo" > foo.log.fifo
$ echo "bar" > foo.log.fifo
$ echo "baz" > foo.log.fifo
$ cat foo.log
Tue, 20 Nov 2012 15:32:56 +0400 foo
Tue, 20 Nov 2012 15:33:27 +0400 bar
Tue, 20 Nov 2012 15:33:30 +0400 baz
यह काम किस प्रकार करता है:
mkfifo
एक नामित पाइप बनाता है
while true; do sed ... ; done
एक अनंत लूप चलाता है और प्रत्येक पुनरावृत्ति पर यह अपने मानक इनपुट पर sed
पुनर्निर्देशन के साथ चलता है foo.log.fifo
; sed
इनपुट डेटा की प्रतीक्षा में ब्लॉक और फिर प्राप्त संदेश को संसाधित करता है और इसे मानक आउटपुट पर प्रिंट करता है foo.log
।
इस बिंदु पर आपको एक नया टर्मिनल विंडो खोलना होगा क्योंकि लूप वर्तमान टर्मिनल पर कब्जा कर लेता है।
echo ... > foo.log.fifo
अपने मानक आउटपुट के लिए एक संदेश प्रिंट करता है, जो पंद्रह फ़ाइल में रीडायरेक्ट sed
होता है और इसे प्राप्त करता है और इसे संसाधित करता है और एक नियमित फ़ाइल को लिखता है।
महत्वपूर्ण नोट फीफो है, जैसे कि किसी भी अन्य पाइप का कोई मतलब नहीं है अगर उसका एक पक्ष किसी भी प्रक्रिया से जुड़ा नहीं है। यदि आप एक पाइप को लिखने की कोशिश करते हैं तो वर्तमान प्रक्रिया तब तक अवरुद्ध हो जाएगी जब तक कोई पाइप के दूसरी तरफ डेटा नहीं पढ़ेगा। यदि आप पाइप से पढ़ना चाहते हैं तो प्रक्रिया तब तक अवरुद्ध रहेगी जब तक कोई व्यक्ति पाइप को डेटा नहीं लिखेगा। sed
उदाहरण में पाश से ऊपर कुछ भी नहीं (सोता) करता है जब तक आप ऐसा echo
।
अपनी विशेष स्थिति के लिए आप केवल लॉग इन संदेशों को पंद्रह फ़ाइल में लिखने के लिए अपने एप्लिकेशन को कॉन्फ़िगर करते हैं। यदि आप इसे कॉन्फ़िगर नहीं कर सकते हैं - बस मूल लॉग फ़ाइल को हटा दें और एक फीनो फ़ाइल बनाएँ। लेकिन फिर से ध्यान दें कि अगर sed
लूप किसी कारण से मर जाएगा - आपके प्रोग्राम को write
फ़ाइल में प्रयास करने पर अवरुद्ध कर दिया जाएगा जब तक कि कोई read
पंद्रह से नहीं होगा ।
लाभ वर्तमान टाइमस्टैम्प का मूल्यांकन है और एक संदेश से जुड़ा हुआ है क्योंकि प्रोग्राम इसे फ़ाइल में लिखता है।
tailf
लॉग को लिखने और अधिक स्वतंत्र प्रसंस्करण के लिए आप दो नियमित फ़ाइलों का उपयोग कर सकते हैं tailf
। एक आवेदन एक कच्ची फ़ाइल को संदेश लिखेगा और दूसरी प्रक्रिया नई लाइनें पढ़ेगी (अतुल्यकालिक रूप से लिखने के लिए) और दूसरी फ़ाइल पर लिखने के साथ डेटा संसाधित करें।
आइए एक उदाहरण लेते हैं:
# will occupy current shell
$ tailf -n0 bar.raw.log | while read line; do echo "$(date -R) $line" >> bar.log; done;
$ echo "foo" >> bar.raw.log
$ echo "bar" >> bar.raw.log
$ echo "baz" >> bar.raw.log
$ cat bar.log
Wed, 21 Nov 2012 16:15:33 +0400 foo
Wed, 21 Nov 2012 16:15:36 +0400 bar
Wed, 21 Nov 2012 16:15:39 +0400 baz
यह काम किस प्रकार करता है:
रन tailf
प्रक्रिया जो लिखने का पालन करेगी bar.raw.log
और उन्हें अनंत while read ... echo
लूप पर पुनर्निर्देशित मानक आउटपुट पर प्रिंट करेगी । यह लूप दो क्रियाएं करता है: मानक इनपुट से डेटा को बफर वेरिएबल तक पढ़ा जाता है line
और फिर निम्न बफर डेटा के साथ उत्पन्न टाइमस्टैम्प को लिखें bar.log
।
को कुछ संदेश लिखें bar.raw.log
। आपको इसे एक अलग टर्मिनल विंडो में करना होगा क्योंकि पहले वाले का कब्जा tailf
होगा, जो राइट्स का पालन करेगा और अपना काम करेगा। काफी सरल।
यदि आप मारते हैं तो मुकदमा आपका आवेदन अवरुद्ध नहीं होगा tailf
। विपक्ष कम सटीक टाइमस्टैम्प और लॉग फ़ाइलों को डुप्लिकेट कर रहा है।
tailf
, आपके द्वारा इसे उपयोग करने का सही तरीका जोड़ा गया है। वास्तव में जिस तरह tailf
से यह अधिक सुरुचिपूर्ण लगता है, लेकिन मैंने उम्मीद के साथ पंद्रह रास्ता अपनाया, यह किसी के लिए उपयोगी होगा।
आप प्रति ts
लिपि का उपयोग कर सकते हैं moreutils
:
$ echo test | ts %F-%H:%M:%.S
2012-11-20-13:34:10.731562 test
दिमित्री वासिलिनोव के जवाब से संशोधित।
बैश स्क्रिप्ट में, आप टाइमस्टैम्प लाइन के साथ आउटपुट को रीडायरेक्ट और रैप कर सकते हैं।
कब इस्तेमाल करें:
tailf
लिए, लॉग फ़ाइल के लिए उपयोग करना बेहतर है जैसा कि दिमित्री वासिलिनोव ने कहा।एक उदाहरण का नाम foo.sh
:
#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)
echo "foo"
sleep 1
echo "bar" >&2
sleep 1
echo "foobar"
और परिणाम:
$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar
यह काम किस प्रकार करता है
exec &>
एक ही स्थान पर stdout और stderr पुनर्निर्देशित करें>( ... )
एक अतुल्यकालिक आंतरिक कमांड के लिए पाइप आउटपुटउदाहरण के लिए:
पाइप टाइमस्टैम्प और फ़ाइल में प्रवेश करें
#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)
echo "some script commands"
/path-to/some-thrid-party-programs
या टाइमस्टैम्प प्रिंट करें और स्टडआउट में लॉग इन करें
#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line"; done;)
echo "some script commands"
/path-to/some-thrid-party-programs
फिर उन्हें /etc/crontab
सेटिंग में सहेजें
* * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
मैंने ts
इस तरह से एक स्क्रिप्ट के लिए एक त्रुटि लॉग में एक टाइम स्टैम्प के साथ एक प्रविष्टि प्राप्त करने के लिए उपयोग किया था जो मैं एक दूरस्थ होस्ट के आँकड़ों से भरा कैक्टि प्राप्त करने के लिए उपयोग करता हूं।
कैक्टि का परीक्षण करने के लिए मैं rand
कुछ यादृच्छिक मूल्यों को जोड़ने के लिए उपयोग करता हूं जो मैं अपने सिस्टम के तापमान की निगरानी के लिए तापमान ग्राफ के लिए उपयोग करता हूं।
Pushmonstats.sh एक स्क्रिप्ट है जो मेरे पीसी के सिस्टम तापमान के आंकड़े एकत्र करती है और इसे एक रास्पबेरी पाई को भेजती है जिस पर कैक्टस चलता है। कुछ समय पहले, नेटवर्क अटक गया था। मुझे केवल SSH का समय मेरी त्रुटि लॉग में मिला। दुर्भाग्य से, उस लॉग में कोई समय प्रविष्टियां नहीं हैं। मुझे नहीं पता था कि लॉग एंट्री में टाइम स्टैम्प कैसे जोड़ा जाता है। इसलिए, इंटरनेट पर कुछ खोजों के बाद, मैं इस पोस्ट पर ठोकर खाई और यही मैंने उपयोग किया ts
।
इसका परीक्षण करने के लिए, मैंने एक अज्ञात विकल्प का उपयोग किया rand
। जिससे स्टादर को एक त्रुटि मिली। इसे पकड़ने के लिए, मैं इसे एक अस्थायी फ़ाइल पर पुनर्निर्देशित करता हूं। फिर मैं फ़ाइल की सामग्री को दिखाने के लिए बिल्ली का उपयोग करता हूं और इसे पाइप ts
करता हूं, एक समय प्रारूप जोड़ता हूं जो मुझे इस पोस्ट पर मिला और अंत में इसे त्रुटि फ़ाइल में लॉग इन करें। फिर मैं अस्थायी फ़ाइल की सामग्री को साफ करता हूं, अन्यथा मुझे उसी त्रुटि के लिए दोहरी प्रविष्टियां मिलती हैं।
crontab:
* * * * * /home/monusr/bin/pushmonstats.sh 1>> /home/monusr/pushmonstats.log 2> /home/monusr/.err;/bin/cat /home/monusr/.err|/usr/bin/ts %F-%H:%M:%.S 1>> /home/monusr/pushmonstats.err;> /home/monusr/.err
यह मेरी त्रुटि लॉग में निम्नलिखित देता है:
2014-03-22-19:17:53.823720 rand: unknown option -- '-l'
हो सकता है कि यह ऐसा करने का एक बहुत ही सुंदर तरीका नहीं है, लेकिन यह काम करता है। मुझे आश्चर्य है कि अगर वहाँ एक और अधिक सुंदर दृष्टिकोण है।