अंतिम पंक्ति का उपयोग करते हुए पहले अंतिम प्रक्रिया करें


11

मेरे पास एक डेटा फ़ाइल है जिसे मैं awkअंतिम डेटापेट के आधार पर उपयोग करके सामान्य करना चाहता हूं । इसके बाद, मैं डेटा को सामान्य करने के लिए, पहले डेटा बिंदु को एक्सेस करना चाहूंगा, फिर सामान्य रूप से प्रक्रिया करूंगा।

निम्नलिखित विधि, tacदो बार का उपयोग करते हुए , काम करता है, लेकिन, शायद आवश्यकता से अधिक जटिल है।

$ cat file
0 5
1 2
2 3
3 4
$ tac file | awk 'NR==1{norm=$2} {print $1, $2/norm}' | tac
0 1.25
1 0.5
2 0.75
3 1

मेरा प्रश्न निम्नलिखित है: क्या केवल awk का उपयोग करके उपरोक्त परिणाम प्राप्त करना संभव है?

मुझे लगता है कि उत्तर "नहीं, awk फाइल लाइन द्वारा लाइन स्कैन करता है", लेकिन मैं विकल्पों के लिए सुझाव के लिए खुला हूं।

जवाबों:


5

आप इसे awk में दो-पास समाधान के रूप में कर सकते हैं:

awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile

यदि आपका awk का संस्करण ENDFILE ब्लॉक का समर्थन करता है (जैसे GNU awk 4+), तो आप इसे इस तरह कर सकते हैं:

awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile

ध्यान दें कि यह seekफ़ाइल के अंत में अधिक कुशल है पहले कैम का जवाब देखें

व्याख्या

पहला उदाहरण पिछले को याद करके काम करता है $2, अर्थात इसका मूल्यांकन केवल तब किया जाता है जब स्थानीय लाइन काउंटर ( FNR) वैश्विक लाइन काउंटर (? NR) के बराबर हो । nextआदेश, अगली पंक्ति में छोड़ देता है तो इस मामले में यह सुनिश्चित करता है कि अंतिम ब्लॉक केवल मूल्यांकन किया जाता है जब दूसरा तर्क पार्स किया गया है।

दूसरे उदाहरण में इसी तरह के तर्क हैं, लेकिन अंतर्मुखी ब्लॉक का लाभ उठाता है जिसका मूल्यांकन इनपुट-फ़ाइल के अंत तक पहुंचने पर किया जाता है।


पहला उदाहरण ठीक काम करता है, दूसरा नहीं $ awk --version GNU Awk 3.1.8। क्या आप शायद दो इनपुट फ़ाइल को कैसे संभालते हैं और क्या करते हैं, इस पर बहुत छोटी व्याख्या जोड़ सकते हैं next?
बर्नहार्ड

1
@ बर्नहार्ड: संपादन देखें
थोर

6

यदि आपका डेटा स्रोत एक ऐसी फ़ाइल है जिसे कई बार पढ़ा जा सकता है (यानी यह एक स्ट्रीम नहीं है), तो आपको सबसे पहले tail(1)उस डेटा का उपयोग करना चाहिए जिसे आप अंतिम पंक्ति से चाहते हैं और पास करें जो फ़ाइल की अनुक्रमिक प्रसंस्करण के लिए जागृत हो। tailइससे पहले सभी डेटा को पढ़ने की आवश्यकता के बिना अंतिम पंक्ति को पढ़ने के लिए फ़ाइल के अंत की तलाश करेंगे।

awk -v norm=$(tail -n 1 file | cut -d' ' -f2) '{print $1, $2/norm}' file

यह बड़ी फ़ाइलों पर एक बड़ी जीत होगी, जहां पूरी फाइल बफर कैश में फिट नहीं होगी (इसका अर्थ है कि इसे डिस्क से दो बार पढ़ना होगा, प्रत्येक पास के लिए एक बार), और स्कैन करने की आवश्यकता नहीं होने से कुछ हद तक मदद मिलेगी अंतिम पंक्ति में जाने के लिए इनपुट छोटी फ़ाइलें दो-पास दृष्टिकोण के लिए बहुत अंतर नहीं दिखा सकती हैं।


3

आप उन्हें एक सरणी में लोड कर सकते हैं और इसे पीछे की ओर पढ़ सकते हैं:

awk '{x[i++]=$0} END{for (j=i-1; j>=0;) print x[j--] }'

आप इसे और अधिक कुशलता से कर सकते हैं, लेकिन इस तरह का चित्रण इसके awkलिए सही उपकरण क्यों नहीं है। tacजहाँ उपलब्ध हो, का उपयोग करना जारी रखें , जीएनयू टैक आम तौर पर इस नौकरी के लिए विभिन्न प्रकार के उपकरणों में से सबसे तेज़ है।


मैं मानता हूं, for-लूप का उपयोग awkकरना समाधान नहीं है।
बर्नहार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.