2011-11-28 26 views
10

मैं सभी पंक्तियों में से प्रत्येक पंक्ति में मूल्य के प्रतिशत की गणना करना चाहता हूं और इसे एक और कॉलम के रूप में जोड़ना चाहता हूं।प्रतिशत के साथ कॉलम को कैसे जोड़ें

1 10  
2 10 
3 20 
4 40 

जोड़ा तीसरे दूसरा स्तंभ में मानों के आधार पर गणना प्रतिशत देख स्तंभ के साथ वांछित उत्पादन:

1 10 12.50 
2 10 12.50 
3 20 25.00 
4 40 50.00 

मैं इसे अपने आप करने की कोशिश की है, लेकिन जब मैं इनपुट (सीमांकक \ t है) सभी लाइनों के लिए गणना की गई कुल मुझे पता नहीं था कि शेष रेखा को अपरिवर्तित कैसे संरक्षित किया जाए। मदद के लिए बहुत बहुत धन्यवाद!

उत्तर

12

यहां आपको एक पास कदम awk समाधान -

awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file

[jaypal:~/Temp] cat file 
1 10  
2 10 
3 20 
4 40 
[jaypal:~/Temp] awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file 
1 10 12.5 
2 10 12.5 
3 20 25 
4 40 50 

अद्यतन: यदि टैब एक उत्पादन में आवश्यक है तो बस ओएफएस चर "\ t" करने के लिए निर्धारित किया है।

[jaypal:~/Temp] awk -v OFS="\t" 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file 
1 10 12.5 
2 10 12.5 
3 20 25 
4 40 50 

पैटर्न {कार्रवाई} बयान के ब्रेकआउट:

  • पहले पैटर्न NR==FNR है। एफएनआर अजीब अंतर्निहित चर है जो किसी दिए गए फ़ाइल में रिकॉर्ड्स की संख्या (डिफ़ॉल्ट रूप से एक नई लाइन से अलग किया जाता है) का ट्रैक रखता है। तो हमारे मामले में एफएनआर होगा 4. एनआर एफएनआर के समान है लेकिन यह 0 पर रीसेट नहीं होता है। यह बढ़ता जा रहा है। तो हमारे मामले में एनआर 8.

  • यह पैटर्न केवल पहले 4 रिकॉर्ड के लिए सच होगा और यह वही है जो हम चाहते हैं। 4 रिकॉर्ड के माध्यम से समझने के बाद, हम कुल को एक चर a पर असाइन कर रहे हैं। ध्यान दें कि हमने इसे प्रारंभ नहीं किया था। awk में हमें यह नहीं करना है। हालांकि, अगर पूरे कॉलम 2 0 है तो यह तोड़ देगा। तो आप दूसरे एक्शन स्टेटमेंट में एक कथन कथन डालकर इसे संभाल सकते हैं। मैं केवल विभाजन करता हूं यदि कोई> 0 अन्य 0 या कुछ से विभाजन कहता है।

  • next आवश्यक है क्योंकि हम वास्तव में निष्पादित करने के लिए दूसरे पैटर्न {action} कथन नहीं चाहते हैं। next आगे की कार्रवाइयों को रोकने और अगले रिकॉर्ड में जाने के लिए अजीब बताता है।

  • एक बार चार रिकॉर्ड पार्स किए जाने के बाद, अगला पैटर्न {action} शुरू होता है, जो कि बहुत सीधे आगे है। प्रतिशत के साथ प्रतिशत और प्रिंट कॉलम 1 और 2 के साथ प्रतिशत के साथ।

नोट:टिप्पणी में आपका उल्लेख @lhf रूप में, यह एक लाइनर केवल जब तक आप डेटा किसी फ़ाइल में निर्धारित किया है के रूप में काम करेंगे। यदि आप पाइप के माध्यम से डेटा पास करते हैं तो यह काम नहीं करेगा।

टिप्पणी में, वहाँ एक चर्चा तरीके एक pipe बजाय एक file से इस इनपुट awk one-liner ले बनाने के लिए चल रहा है। वैसे मैं एकमात्र तरीका सोच सकता था कि कॉलम मानों को array में संग्रहीत करना था और उसके बाद प्रत्येक मान को उनके प्रतिशत के साथ थूकने के लिए for loop का उपयोग करना था।

अब arraysawk में associative यानी सरणियों से बाहर मूल्यों खींच उसी क्रम में नहीं होगा के रूप में वे में चला गया। तो अगर यह ठीक उसके बाद निम्न एक लाइनर काम करना चाहिए है कर रहे हैं और क्रम में कभी नहीं कर रहे हैं।

[jaypal:~/Temp] cat file 
1 10  
2 10 
3 20 
4 40 

[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}' 
2 10 12.5 
3 20 25 
4 40 50 
1 10 12.5 

उन्हें क्रम में पाने के लिए आपको पाइप sort लिए परिणाम कर सकते हैं।

[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}' | sort -n 
1 10 12.5 
2 10 12.5 
3 20 25 
4 40 50 
+0

यह है। धन्यवाद! – Martin

+0

कोई समस्या नहीं है। :) मैं संदर्भ के लिए कुछ स्पष्टीकरण में डाल देंगे। –

+1

अच्छा, लेकिन वास्तव में एक-पास नहीं है। विशेष रूप से, इसे फ़िल्टर के रूप में उपयोग नहीं किया जा सकता है, यानी, stdin से पढ़ना। – lhf

1

आपको इसे %% के रूप में बचाना होगा। उदाहरण के लिए:

printf("%s\t%s\t%s%%\n", $1, $2, $3) 
+0

धन्यवाद, क्षमा करें अगर इसे प्रश्न में सही ढंग से समझाया नहीं गया है - मुझे% साइन (मुझे इसकी आवश्यकता नहीं है) में समस्या नहीं है, मेरी समस्या यह है कि मूल्य की गणना कैसे करें। – Martin

+0

ओह ... ठीक है! समस्या का गलत वर्णन करने के लिए खेद है! – jsalonen

2

आप शायद वहाँ बेहतर तरीका है गुजरता

#!/bin/bash 

total=$(awk '{total=total+$2}END{print total}' file) 
awk -v total=$total '{ printf ("%s\t%s\t%.2f\n", $1, $2, ($2/total)*100)}' file 
+0

धन्यवाद। यह भी काम करता है, हालांकि मुझे जयपाल द्वारा उपयोग किए जाने वाले समाधान का उपयोग करना आसान था, इसलिए मैंने जवाब के रूप में अपना समाधान चुना। – Martin

0

के एक जोड़े में कर सकते हैं, लेकिन मैं फ़ाइल दो बार से होकर गुजरेगा।

BEGIN { 
     ## Tab as field separator. 
     FS = "\t"; 
} 

## First pass of input file. Get total from second field. 
ARGIND == 1 { 
     total += $2; 
     next; 
} 

## Second pass of input file. Print each original line and percentage as third field. 
{ 
     printf("%s\t%2.2f\n", $0, $2 * 100/total); 
} 

भागो मेरी linux बॉक्स में स्क्रिप्ट:

gawk -f script.awk infile infile 

और परिणाम

1  10 
2  10 
3  20 
4  40 

'script.awk' की सामग्री:

'infile' की सामग्री:

1  10  12.50 
2  10  12.50 
3  20  25.00 
4  40  50.00 
+0

धन्यवाद। यह भी काम करता है। – Martin

संबंधित मुद्दे