একটি আদেশ থেকে আউটপুট প্রতিটি লাইন একটি টাইমস্ট্যাম্প প্রস্তুত


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
আমি কীভাবে এই সম্পর্কে জানতে পারি না?!?!?! এই আশ্চর্যজনকভাবে লেজ - পরিপূরক! tail -f /tmp/script.results.txt | ts
ব্রুনো ব্রোনোস্কি

সাইগউইন সম্পর্কে কি? অনুরূপ কিছু আছে? এটি জোয়ের মুর্টালগুলি উপস্থিত রয়েছে বলে মনে হয় না।
ক্রেজিপেনগুইন

3
আমার কাছে টিএস কমান্ড না থাকলে আমার কী ব্যবহার করা উচিত?
একসিস

1
যদি এটি কাজ না করে তবে ssh -v 127.0.0.1 2>&1 | ts
স্টাডারকে স্টডআউটে

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
জাতীয়ভাবে সংশোধন করে

100

প্রথমত, যদি আপনি এই টাইমস্ট্যাম্পগুলি আসলে কোনও ইভেন্টের প্রতিনিধিত্ব করার প্রত্যাশা করে থাকেন তবে মনে রাখবেন যে যেহেতু অনেকগুলি প্রোগ্রাম লাইন বাফারিং করে (অন্যদের তুলনায় কিছুটা আক্রমণাত্মকভাবে), সুতরাং এটির মূল লাইনের সময়টিকে খুব কাছাকাছি মনে করা গুরুত্বপূর্ণ কোনও ক্রিয়া সংঘটিত হওয়ার টাইমস্ট্যাম্পের চেয়ে ছাপানো হয়েছে।

আপনি এটিও পরীক্ষা করতে চাইতে পারেন যে আপনার কমান্ডটিতে ইতিমধ্যে এটি করার জন্য উত্সর্গীকৃত কোনও ইনবিল্ট বৈশিষ্ট্য নেই। উদাহরণস্বরূপ, ping -Dকিছু pingসংস্করণে উপস্থিত রয়েছে এবং প্রতিটি লাইনের আগে ইউনিক্সের সূচনাকালীন সময়টি মুদ্রণ করে। যদি আপনার কমান্ডটিতে নিজস্ব পদ্ধতি না থাকে তবে অন্যদের মধ্যে কয়েকটি পদ্ধতি ও সরঞ্জাম ব্যবহার করা যেতে পারে:

পসিক্স শেল

মনে রাখবেন যেহেতু অনেকগুলি শাঁস তাদের স্ট্রিংগুলি অভ্যন্তরীণভাবে সিস্ট্রিং হিসাবে সংরক্ষণ করে, যদি ইনপুটটিতে নাল অক্ষর থাকে ( \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
এখানে একটি সমস্যা হ'ল অনেক প্রোগ্রামগুলি আরও বেশি আউটপুট বাফারিং চালু করে যখন তাদের স্টাডআউটটি টার্মিনালের পরিবর্তে পাইপ হয়।
সিজেএম

3
@ সিজেএম - সত্য। কিছু আউটপুট বাফারিং ব্যবহার করে হ্রাস করা যেতে পারে stdbuf -o 0, তবে প্রোগ্রামটি যদি ম্যানুয়ালি তার আউটপুট বাফারিং পরিচালনা করে তবে এটি সাহায্য করবে না (যদি না আউটপুট বাফারটির আকারটি অক্ষম / কমানোর বিকল্প না থাকে)।
ক্রিস ডাউন

2
অজগর জন্য, আপনি লাইন বাফারিং অক্ষম করতে পারেনpython -u
ইবিজামান

@ বিডব্লট নং সমস্তগুলিকে ... for x in sys.stdinপ্রথমে স্মৃতিতে বাফার না করে লাইনগুলিতে পুনরাবৃত্তি করে।
ক্রিস ডাউন

এটি করুন এবং আপনি বাফার পাবেন ... 1 1 1 1 1 এর জন্য; ঘুমাও 1; echo; সম্পন্ন | পাইথন-সি 'আমদানি কর, সময় ", টাইমস.এমটাইম ()), লাইন)) লাইনে সিজ.স্টদিন))) '
চককট্রিল

41

লাইন বাই লাইন ডেল্টা পরিমাপের জন্য, জ্ঞোমন চেষ্টা করুন ।

এটি একটি কমান্ড লাইন ইউটিলিটি, কিছুটা মুর্টিলের টিএস-এর মতো, অন্য কমান্ডের স্ট্যান্ডার্ড আউটপুটে টাইমস্ট্যাম্প তথ্য প্রিপেন্ড করতে। দীর্ঘ-চলমান প্রক্রিয়াগুলির জন্য দরকারী যেখানে আপনি এত দীর্ঘ সময় নিয়ে যাচ্ছেন তার একটি recordতিহাসিক রেকর্ড চাই।

জ্ঞোমনকে কোনও কিছুর পাইপ দেওয়া প্রতিটি লাইনের জন্য একটি টাইমস্ট্যাম্প তৈরি করে, এটি নির্দেশ করে যে সেই রেখাটি বাফারের শেষ লাইনটি কত দীর্ঘ ছিল - এটি পরবর্তী লাইনটি প্রদর্শিত হতে কতক্ষণ সময় নিয়েছিল। ডিফল্টরূপে, জ্ঞোমন প্রতিটি লাইনের মধ্যবর্তী সময় সেকেন্ডে প্রদর্শন করবে তবে তা কনফিগারযোগ্য।

জ্ঞানমন ডেমো


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এবং আউটপুটটিতে প্রদর্শিত হবে না। এর সঠিক বিবরণের জন্য আপনার শেলের ম্যানুয়াল পৃষ্ঠাটি দেখুন Consult-c

এই সমাধানটি পরীক্ষা করে tail -f /var/log/syslogএবং (যেমন আপনি সম্ভবত অনুমান করতে পারেন) আমার ওয়াইফাইকে সংযোগ বিচ্ছিন্ন এবং পুনরায় সংযোগ স্থাপন, উভয় dateএবং syslogবার্তাগুলির দ্বারা সরবরাহিত যথাযথ টাইম-স্ট্যাম্পিং দেখিয়েছে

বাশ কোনও বোর্ন-জাতীয় শেল দ্বারা প্রতিস্থাপিত হতে পারে, হয় kshবা dashকমপক্ষে -cবিকল্প রয়েছে এমনগুলি দিয়ে সম্পন্ন করা যেতে পারে ।

সম্ভাব্য সমস্যা:

সমাধানটির দরকার হয় xargs, যা পসিএক্স অনুবর্তী সিস্টেমগুলিতে উপলব্ধ, তাই বেশিরভাগ ইউনিক্সের মতো সিস্টেমগুলি beেকে রাখা উচিত। স্পষ্টতই যদি আপনার সিস্টেমটি পজিক্স-নন বা পসিক্স অনুগত হয় বা কাজ করে নাGNU findutils


5

আমি উপরে মন্তব্য করতে পছন্দ করতাম তবে আমি সম্মানজনকভাবে পারি না। যাইহোক, উপরের পার্ল নমুনা নিম্নরূপে unfuffered করা যেতে পারে:

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

প্রথম '$ |' স্টাটআউট দ্বিতীয়টি স্টার্ডারকে বর্তমান ডিফল্ট আউটপুট চ্যানেল হিসাবে সেট করে এবং এটি আনফার করে। যেহেতু সিলেক্ট $ | এর মূল সেটিংটি ফেরত দেয়, কোনও নির্বাচনের ভিতরে নির্বাচন মোড়ানো করে, আমরা আবার reset | পুনরায় সেটও করি তার ডিফল্ট, STDOUT এ।

এবং হ্যাঁ, আপনি যেমন 'এন পেস্ট কাটা করতে পারেন। আমি সুগমতার জন্য এটি বহু-রেখাযুক্ত করেছি।

এবং যদি আপনি সত্যিই সুনির্দিষ্ট পেতে চান (এবং আপনার কাছে সময় :: হায়ার্স ইনস্টল করা আছে):

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ফাংশন তৈরি করতে পারেন বাশ সংস্করণের উপর নির্ভর করে:

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

ইউপিডি: এর পরিবর্তে $(date +"${TIMESTAMP_FORMAT}")এটি ব্যবহার করা ভাল $(exec date +"${TIMESTAMP_FORMAT}")বা এমনকি $(exec -c date +"${TIMESTAMP_FORMAT}")খুব দ্রুত গতি সম্পন্ন কার্যকর execution


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
সমাধানটি নিকটে, তবে দীর্ঘ সময় ধরে পৃথক আউটপুট এলে সঠিকভাবে টাইমস্ট্যাম্প করে না। এছাড়াও, আপনি ব্যাকটিকগুলি ব্যবহার করছেন এবং উদ্ধৃত করেন নি $1। এটা ভাল স্টাইল নয়। সর্বদা চলকগুলি উদ্ধৃত করুন। এছাড়াও, আপনি ব্যবহার করছেন echo, যা বহনযোগ্য নয়। এটি ঠিক আছে, তবে কিছু সিস্টেমে সঠিকভাবে কাজ নাও করতে পারে।
সের্গেই কলডিয়াজনি

এটি পরীক্ষার পরে, আপনি একদম ঠিক বলেছেন ... dateপ্রতিটি লাইনে নতুন করে মূল্যায়ন করার কোনও উপায় কি আপনি জানেন , বা এটি বেশ আশাবাদী?
রায়ান 1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.