कॉन्टेक्टनेट लाइनों को पहले कॉलम द्वारा awk या sed


12

मैं awkनिम्नलिखित स्थिति में कैसे उपयोग कर सकता हूं ?

मैं एक ही कॉलम के साथ शुरू होने वाली लाइनों को संक्षिप्त करना चाहता हूं। बाद में शामिल होने के केवल पहले कॉलम रखा जाता है (इस मामले में aaa, www, hhh)।

फ़ाइल स्थान-या टैब-अलग हो सकती है।

उदाहरण इनपुट:

aaa bbb ccc ddd NULL NULL NULL
aaa NULL NULL NULL NULL NULL NULL
aaa bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy
hhh 111 333 yyy ooo hyy NULL

वांछित उत्पादन:

aaa bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc NULL NULL NULL NULL
www yyy hhh NULL NULL NULL NULL
hhh 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL

इसकी पृष्ठभूमि यह है कि मैं एक बहुत ही सरल फ़ाइल-आधारित डेटाबेस सेट करना चाहता हूं, जहां पहला कॉलम हमेशा इकाई के लिए पहचानकर्ता होता है। समान पहचानकर्ता कॉलम पर आधारित सभी पंक्तियों को संक्षिप्त किया जाता है।


1
uuuलाइन कहां से आई (आउटपुट में)?
सईदन

माफ करना मेरा बुरा। मैं इसे संपादित करूँगा।
छोटे

जवाबों:


8

Awk का उपयोग करके प्रत्येक पंक्ति में पहला कॉलम प्राप्त करने के लिए आप निम्नलिखित कार्य कर सकते हैं:

< testfile awk '{print $1}'
aaa
aaa
aaa
www
hhh
hhh

बाकी लाइनों के लिए ये आपकी चाबियां हैं। तो आप एक हैश तालिका बना सकते हैं, कुंजी के रूप में पहला कॉलम और मूल्य के रूप में लाइन के दूसरे कॉलम का उपयोग कर सकते हैं:

< testfile awk '{table[$1]=table[$1] $2;} END {for (key in table) print key " => " table[key];}'
www => yyy
aaa => bbbNULLbbb
hhh => 111111

स्तंभ 2 के साथ शुरू होने वाली संपूर्ण शेष पंक्ति प्राप्त करने के लिए, आपको सभी कॉलम एकत्र करने होंगे:

< testfile awk '{line="";for (i = 2; i <= NF; i++) line = line $i " "; table[$1]=table[$1] line;} END {for (key in table) print key " => " table[key];}'
www => yyy hhh NULL NULL NULL NULL 
aaa => bbb ccc ddd NULL NULL NULL NULL NULL NULL NULL NULL NULL bbb ccc    NULL NULL NULL NULL 
hhh => 111 333 yyy ooo hyy uuuioooy 111 333 yyy ooo hyy NULL 

हाय, हाँ, यह वास्तव में हैश तालिकाओं को तोड़ने की जरूरत है। धन्यवाद!
छोटे

2
@ छोटे - मैं आदेश को संरक्षित करने की आवश्यकता मान रहा था। क्या यह मामला नहीं है (यह जवाब हैशिंग तंत्र के अनुरूप आदेश पैदा करता है, आपका मूल आदेश नहीं)?
ire_and_curses

3

कोई और अजीब या सेड में जवाब दे सकता है, लेकिन एक पायथन संस्करण सीधा है और आपके लिए मददगार हो सकता है।

#!/usr/bin/env python

input_file = 'input.dat'
in_fh      = open(input_file, 'r')

input_order = []
seen        = {}
for line in in_fh:    
    # Remove the newline character...
    line = line[:-1]

    # Separate the first column from the rest of the line...
    key_col, sep, rest_of_line = line.partition(" ")
    rest_of_line = sep + rest_of_line  

    # If we've seen this key already, concatenate the line...
    if key_col in seen:
        seen[key_col] += rest_of_line
    # ...otherwise, record the ordering, and store the new info
    else:
        input_order.append(key_col)
        seen[key_col] = rest_of_line

in_fh.close()

# Dump the ordered output to stdout
for unique_col in input_order:
    print unique_col + seen[unique_col]

बहुत ही शांत। अपने शून्य अनुभव अजगर के साथ मैंने स्क्रिप्ट को संपादित करने में भी कामयाबी हासिल कर ली है कि यह इनपुट फ़ाइल के नाम के रूप में पहला तर्क देता है :)
छोटा

2

यह कोरुटिल्स का एक दिलचस्प अनुप्रयोग है, मुझे संदेह है कि यह बड़े इनपुट के साथ बहुत कुशल नहीं है क्योंकि यह इनपुट में प्रत्येक पंक्ति के लिए जुड़ता है।

touch outfile
while read; do
  join -a1 -a2 outfile <(echo $REPLY) > tmp
  mv tmp outfile
done < infile

इसे सुधारने के लिए दक्षता, बचत outfileऔर tmpएक रैमडिस्क में मदद मिल सकती है।

संपादित करें

या अस्थायी फ़ाइलों के बिना:

out=""
while read; do
  out=$(join -a1 -a2 <(echo -n "$out") <(echo -n "$REPLY"))
done < infile

echo "$out"

2

और यहाँ एक पर्ल एक लाइनर है:

$ perl -e 'my %h; while(<>){chomp; @a=split(/\s+/); $k=shift(@a); $h{$k}.=join(" ", @a) . " "; } map{$h{$_}=~s/\s*$//; print "$_ $h{$_}\n}keys(%hash);' infile
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.