एक कमांड से आउटपुट की प्रत्येक पंक्ति के लिए टाइमस्टैम्प को प्रस्तुत करना


182

मैं एक कमांड से आउटपुट की प्रत्येक पंक्ति के लिए टाइमस्टैम्प तैयार करना चाहता हूं। उदाहरण के लिए:

foo
bar
baz

बन जाएगा

[2011-12-13 12:20:38] foo
[2011-12-13 12:21:32] bar
[2011-12-13 12:22:20] baz

... जहाँ समय उपसर्ग किया जा रहा है वह समय जिस पर लाइन छपी थी। इसे कैसे प्राप्त किया जा सकता है?


जवाबों:


274

अधिक जानकारी में tsयह अच्छी तरह से शामिल है:

command | ts '[%Y-%m-%d %H:%M:%S]'

यह एक लूप की आवश्यकता को भी समाप्त करता है, आउटपुट की प्रत्येक पंक्ति में एक टाइमस्टैम्प होगा।

$ echo -e "foo\nbar\nbaz" | ts '[%Y-%m-%d %H:%M:%S]'
[2011-12-13 22:07:03] foo
[2011-12-13 22:07:03] bar
[2011-12-13 22:07:03] baz

आप जानना चाहते हैं कि वह सर्वर कब वापस आया था जिसे आपने पुनः आरंभ किया था? बस चलाएं ping | ts, समस्या हल हो गई: डी।


8
मुझे इस बारे में कैसे पता नहीं चला?!?!?!? इस पूरक पूंछ -f आश्चर्यजनक! tail -f /tmp/script.results.txt | ts
बजे ब्रूनो ब्रोंस्की

साइबरविन के बारे में क्या? क्या ऐसा ही कुछ है? ऐसा प्रतीत नहीं होता है कि जॉय की विधियां हैं।

3
अगर मेरे पास ts कमांड नहीं है, तो मुझे क्या उपयोग करना चाहिए?
एक्कासिस

1
यह काम नहीं कर रहा है, stderr पुनः निर्देशित stdout करने के लिए जैसे कोशिशssh -v 127.0.0.1 2>&1 | ts
jchook

3
मुझे लगता है कि पैरामीटर इंगित करना -sउपयोगी है। जैसा कि कमांड के रनटाइम को प्रदर्शित करता है। मैं व्यक्तिगत रूप से दोनों का उपयोग कर की तरह है tsऔर ts -sएक ही समय में। इस तरह दिखता है: command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'। यह लॉग लाइनों को इस तरह से तैयार करता है:[2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
BrainStone

100

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

आप यह भी जांच सकते हैं कि आपके कमांड में पहले से इनबिल्ट फीचर नहीं है जो ऐसा करने के लिए समर्पित है। एक उदाहरण के रूप ping -Dमें, कुछ pingसंस्करणों में मौजूद है , और प्रत्येक पंक्ति से पहले यूनिक्स के युग के बाद के समय को प्रिंट करता है। यदि आपके आदेश में अपना स्वयं का तरीका नहीं है, हालांकि, कुछ तरीके और उपकरण हैं जिन्हें दूसरों के बीच नियोजित किया जा सकता है:

POSIX खोल

इस बात को ध्यान में रखें कि चूँकि कई गोले अपने तार को आंतरिक रूप से क्रासिंग के रूप में संग्रहीत करते हैं, अगर इनपुट में शून्य वर्ण ( \0) होता है, तो यह समय से पहले समाप्त हो सकता है।

command | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done

जीएनयू जागा

command | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }'

पर्ल

command | perl -pe 'use POSIX strftime; print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

अजगर

command | python -c 'import sys,time;sys.stdout.write("".join(( " ".join((time.strftime("[%Y-%m-%d %H:%M:%S]", time.localtime()), line)) for line in sys.stdin )))'

माणिक

command | ruby -pe 'print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")'

3
यहाँ एक समस्या यह है कि कई कार्यक्रम बफ़रिंग को तब और अधिक चालू करते हैं जब उनका स्टडआउट टर्मिनल के बजाय एक पाइप होता है।
cjm

3
@cjm - सच है। कुछ आउटपुट बफ़रिंग का उपयोग करके कम किया जा सकता है stdbuf -o 0, लेकिन यदि प्रोग्राम मैन्युअल रूप से अपने आउटपुट बफ़रिंग को संभाल रहा है, तो यह मदद नहीं करेगा (जब तक कि आउटपुट बफर के आकार को अक्षम / कम करने का विकल्प नहीं है)।
क्रिस डाउन

2
अजगर के लिए, आप के साथ लाइन बफरिंग निष्क्रिय कर सकते हैंpython -u
ibizaman

@Bwmat नंबर ... for x in sys.stdinपहले मेमोरी में उन सभी को बफरिंग के बिना लाइनों पर पुनरावृत्त करता है।
क्रिस डाउन

ऐसा करें और आपको बफरिंग मिलती है ... 1 1 1 1 1 1 में; सो जाओ 1; गूंज; हो गया | python -c 'sys, time; sys.stdout.write (""। join ("" (.join) (time.strftime ("[% Y-% m-% d% H:% M:% S]] ", time.gmtime ()), लाइन)) sys.stdin में लाइन के लिए))) ''
ChuckCottrill

41

एक लाइन-बाय-लाइन डेल्टा माप के लिए, सूक्ति का प्रयास करें ।

यह एक कमांड लाइन उपयोगिता है, थोडा और अधिक टीटीएस की तरह, टाइमस्टैम्प की जानकारी को दूसरे कमांड के मानक आउटपुट में प्रस्तुत करने के लिए। लंबे समय तक चलने वाली प्रक्रियाओं के लिए उपयोगी जहाँ आप इतना लंबा समय ले रहे हैं का एक ऐतिहासिक रिकॉर्ड चाहते हैं।

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

सूक्ति प्रदर्शन


tsलाइव प्रक्रियाओं का उपयोग करते समय एक शानदार विकल्प की तरह दिखता है। जबकि tsगैर-संवादात्मक प्रक्रियाओं के लिए बेहतर अनुकूल है।
ब्रेनस्टोन

7

रयान का पद एक दिलचस्प विचार प्रदान करता है, हालांकि, यह कई मामलों में विफल रहता है। साथ परीक्षण करते समय tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1 , मैंने देखा कि टाइमस्टैम्प समान रहता है, भले ही stdoutबाद में सेकंड में अंतर के साथ आता है। इस आउटपुट पर विचार करें:

[2016-07-14 01:44:25] Jul 14 01:44:32 eagle dhclient[16091]: DHCPREQUEST of 192.168.0.78 on wlan7 to 255.255.255.255 port 67 (xid=0x411b8c21)
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: Joining mDNS multicast group on interface wlan7.IPv6 with address fe80::d253:49ff:fe3d:53fd.
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: New relevant interface wlan7.IPv6 for mDNS.

मेरा प्रस्तावित समाधान समान है, हालांकि उचित समय-मुद्रांकन प्रदान करता है और printfइसके बजाय कुछ अधिक पोर्टेबल उपयोग करता हैecho

| xargs -L 1 bash  -c 'printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S )" "$*" ' bash

क्यों bash -c '...' bash? क्योंकि -cविकल्प के कारण , पहला तर्क असाइन किया गया है $0और आउटपुट में दिखाई नहीं देगा। के उचित विवरण के लिए अपने शेल के मैनुअल पेज से परामर्श करें-c

इस समाधान का परीक्षण tail -f /var/log/syslogऔर (जैसा कि आप शायद अनुमान लगा सकते हैं) मेरी वाईफाई को डिस्कनेक्ट और फिर से कनेक्ट कर रहा है, दोनों dateऔर syslogसंदेशों द्वारा प्रदान की गई उचित समय-मुद्रांकन को दिखाया गया है

बैश को किसी भी बॉर्न जैसे शेल द्वारा प्रतिस्थापित किया जा सकता है , kshया तो dashकम से कम या जिनके पास -cविकल्प हो सकता है।

संभावित मुद्दे:

समाधान के लिए आवश्यक है xargs, जो POSIX अनुरूप प्रणालियों पर उपलब्ध है, इसलिए अधिकांश यूनिक्स जैसी प्रणालियों को कवर किया जाना चाहिए। यदि आपका सिस्टम गैर-पॉसिक्स कंप्लेंट है या नहीं है तो जाहिर तौर पर काम नहीं करेगाGNU findutils


5

मैं ऊपर टिप्पणी करना पसंद करता, लेकिन मैं प्रतिष्ठित नहीं कर सकता। फिर भी, ऊपर का पर्ल नमूना निम्नानुसार अप्रभावित हो सकता है:

command | perl -pe 'use POSIX strftime; 
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

पहला '$ |' असंतुष्ट STDOUT। दूसरा सेट वर्तमान डिफ़ॉल्ट आउटपुट चैनल के रूप में सेट करता है और इसे अनबफ़र करता है। चूँकि सेलेक्ट $ की मूल सेटिंग लौटाता है, इसलिए सेलेक्ट के अंदर सेलेक्ट करके, हम $ को भी रिसेट करते हैं | डिफ़ॉल्ट रूप से, STDOUT।

और हाँ, आप 'n' पेस्ट को काट सकते हैं। मैंने इसे सुपाठ्य के लिए बहु-पंक्तिबद्ध किया।

और अगर आप वास्तव में सटीक प्राप्त करना चाहते हैं (और आपके पास समय :: किराए पर स्थापित):

command | perl -pe 'use POSIX strftime; use Time::HiRes gettimeofday;
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    ($s,$ms)=gettimeofday();
                    $ms=substr(q(000000) . $ms,-6);
                    print strftime "[%Y-%m-%d %H:%M:%S.$ms]", localtime($s)'

1
बिना किसी अमानक पैकेज को स्थापित किए बिना, आकर्षण की तरह काम करता है।
जे टेलर

2

अधिकांश उत्तर उपयोग करने का सुझाव देते हैं date, लेकिन यह काफी धीमा है। यदि आपका बैश संस्करण 4.2.0 से अधिक है printf, तो इसके बजाय इसका उपयोग करना बेहतर है , यह बैश बिलिन है। यदि आपको विरासत बैश संस्करणों का समर्थन करने की आवश्यकता है, तो आप logफ़ंक्शन बना सकते हैं, जो bash संस्करण पर निर्भर करता है:

TIMESTAMP_FORMAT='%Y-%m-%dT%H:%M:%S'
# Bash version in numbers like 4003046, where 4 is major version, 003 is minor, 046 is subminor.
printf -v BV '%d%03d%03d' ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]}
if ((BV > 4002000)); then
log() {
    ## Fast (builtin) but sec is min sample for most implementations
    printf "%(${TIMESTAMP_FORMAT})T %5d %s\n" '-1' $$ "$*"  # %b convert escapes, %s print as is
}
else
log() {
    ## Slow (subshell, date) but support nanoseconds and legacy bash versions
    echo "$(date +"${TIMESTAMP_FORMAT}") $$ $*"
}
fi

गति अंतर देखें:

user@host:~$time for i in {1..10000}; do printf "%(${TIMESTAMP_FORMAT})T %s\n" '-1' "Some text" >/dev/null; done

real    0m0.410s
user    0m0.272s
sys     0m0.096s
user@host:~$time for i in {1..10000}; do echo "$(date +"${TIMESTAMP_FORMAT}") Some text" >/dev/null; done

real    0m27.377s
user    0m1.404s
sys     0m5.432s

UPD: इसके बजाय $(date +"${TIMESTAMP_FORMAT}")इसका उपयोग करना $(exec date +"${TIMESTAMP_FORMAT}")या यहां तक ​​कि $(exec -c date +"${TIMESTAMP_FORMAT}")स्पीडअप निष्पादन बेहतर है ।


0

आप इसके साथ कर सकते हैं dateऔर xargs:

... | xargs -L 1 echo `date +'[%Y-%m-%d %H:%M:%S]'` $1

स्पष्टीकरण:

xargs -L 1xargs को इनपुट की प्रत्येक 1 पंक्ति के लिए कार्यवाही कमांड चलाने के लिए कहता है, और यह पहली पंक्ति में गुजरता है क्योंकि यह ऐसा करता है। echo `date +'[%Y-%m-%d %H:%M:%S]'` $1मूल रूप से इसके अंत में इनपुट तर्क के साथ तारीख निकालता है


2
समाधान करीब है, लेकिन यह लंबे समय तक अलग-अलग आउटपुट के लिए ठीक से टाइमस्टैम्प नहीं करता है। इसके अलावा, आप backticks का उपयोग कर रहे हैं और उद्धृत नहीं किया है $1। यह अच्छी शैली नहीं है। हमेशा चर को उद्धृत करें। इसके अलावा, आप उपयोग कर रहे हैं echo, जो पोर्टेबल नहीं है। यह ठीक है, लेकिन कुछ प्रणालियों पर ठीक से काम नहीं कर सकता है।
सर्गी कोलोडियाज़नी

यह परीक्षण करने के बाद, यह प्रतीत होता है कि आप बिल्कुल सही हैं ... क्या आपको dateहर पंक्ति को फिर से मूल्यांकन करने का कोई तरीका पता है , या यह बहुत निराशाजनक है?
रयान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.