2012-10-23 12 views
7

पर रखें मेरे पास एक डेटा फ़ाइल है जिसे मुझे नियमित अभिव्यक्तियों के साथ बदलने की आवश्यकता है। अधिक विशेष रूप से, मुझे पहले 6 कॉलम को समान बनाए रखने की आवश्यकता है, और 7 वें कॉलम से, केवल विषम कॉलम का चयन करें, और उसके बाद लगातार पंक्तियों की प्रत्येक जोड़ी के फ़ील्ड को एक साथ रखें। मुझे पता है कि यह थोड़ा जटिल लगता है इसलिए मैं इसे एक उदाहरण के माध्यम से स्पष्ट कर दूंगा। यह मेरा मूल डेटा फ़ाइल है (यह कॉलम के किसी भी संख्या हो सकती है):अजीब कॉलम का चयन करें, फिर लगातार पंक्तियों के फ़ील्ड को

A B C D E F 11 12 13 14 15 16 17 18 
A B C D E F 21 22 23 24 25 26 27 28 
A B C D E F 31 31 33 34 35 36 37 38 
A B C D E F 41 42 43 44 45 46 47 48 
A B C D E F 51 52 53 54 55 56 57 58 
A B C D E F 61 62 63 64 65 66 67 68 
A B C D E F 71 72 73 74 75 76 77 78 
A B C D E F 81 82 83 84 85 86 87 88 

मैं पता लगा मैं 6 पहले कॉलम बनाए रख सकते हैं और उसके बाद किया जा रहा है

awk '{for (i = 1; i <= NF; i++) if (i < 7 || i % 2 == 1) printf $i OFS}; {print ""} 

साथ अजीब ही हटा भी इस परिणाम:

A B C D E F 11 13 15 17 
A B C D E F 21 23 25 27 
A B C D E F 31 33 35 37 
A B C D E F 41 43 45 47 
A B C D E F 51 53 55 57 
A B C D E F 61 63 65 67 
A B C D E F 71 73 75 77 
A B C D E F 81 83 85 87 

लेकिन उस के बाद मैं इस तरह, लगातार पंक्तियों की प्रत्येक जोड़ी के क्षेत्र को एक साथ रखा करने के लिए है:

A B C D E F 11 21 13 23 15 25 17 27 
A B C D E F 31 41 33 43 35 45 37 47 
A B C D E F 51 61 53 63 55 65 57 67 
A B C D E F 71 81 73 83 75 85 77 87 

मैं पूरी प्रक्रिया बनाने के लिए sed या awk का उपयोग करने के बारे में सोच रहा था, क्योंकि मेरी डेटा फाइलें बहुत बड़ी हैं और मुझे उन्हें कुशलतापूर्वक बदलने की जरूरत है, लेकिन मैं दूसरे रूपांतरण को करने का कोई तरीका नहीं समझ पाया। किसी भी मदद को बहुत सराहा जाएगा।

उत्तर

3

यहाँ एक ही रास्ता GNU awk का उपयोग कर रहा है। script.awk की

awk -f script.awk file.txt 

सामग्री::

{ 
    getline line 
    split(line, array) 
    k = 6 
    n = ((NF - k) % 2 == 0) ? 1 : 0 

    for (i=1; i<=k; i++) { 
     printf $i OFS 
    } 

    for (j=7; j<=NF-n; j+=2) { 
     x = $j OFS array[j] 
     printf (j < NF - n) ? x OFS : x "\n" 
    } 
} 

परिणाम:

A B C D E F 11 21 13 23 15 25 17 27 
A B C D E F 31 41 33 43 35 45 37 47 
A B C D E F 51 61 53 63 55 65 57 67 
A B C D E F 71 81 73 83 75 85 77 87 
+0

मैं वास्तव में आपके उत्तर की सराहना करता हूं, यही वही है जो मैं ढूंढ रहा था। मैं आपके समाधान का प्रयास करूंगा और जिसकी मैं अभी आया हूं, यह जांचने के लिए कि कौन सा तेज़ है (हालांकि पहली नज़र में मुझे लगता है कि आपका बेहतर है)। – Serchu

+1

@ सर्चू: मैंने अपना जवाब संपादित करना समाप्त कर दिया है। मैंने इसे थोड़ा और सामान्य बना दिया है (और थोड़ा और भी गूढ़ है)। अब यह उन फ़ाइलों को संभाल लेंगे जिनमें कॉलम की संख्या या कॉलम की विषम संख्या हो। आप रखने के लिए प्रारंभिक कॉलम की संख्या भी सेट कर सकते हैं। HTH। – Steve

+0

मैं यहां गेटलाइन का उपयोग करने के लिए प्रलोभन को समझता हूं लेकिन इसे टालने के लिए लगभग हमेशा सर्वोत्तम होता है क्योंकि यह सरल आवश्यकताओं को लागू करने में कठोर परिवर्तन करता है (कई अन्य चेतावनियों में - http://awk.info/?tip/getline देखें)। क्या होगा, उदाहरण के लिए, आप अतिरिक्त रूप से 45 की सभी लाइनों की गिनती रखना चाहते हैं? गैर-गेटलाइन समाधान के साथ आप अजीब शरीर में "/ 45/{C++}" जोड़ देंगे, लेकिन गेटलाइन समाधान के साथ आपको ऐसा करने की आवश्यकता है और "अगर (लाइन ~/45 /) {C++}" के बाद " गेटलाइन, जटिल चीजें और केवल एक छोटी, अवधारणात्मक छोटी आवश्यकताओं के लिए डुप्लिकेट कोड बनाना। –

2

इस प्रयास करें:

# d.awk 
{ 
    if (NR % 2 == 1) { 
     a = $7 
     b = $9 
     c = $11 
     d = $13 
    } else { 
     print $1, $2, $3, $4, $5, $6, a, $7, b, $9, c, $11, d, $13 
    } 
} 

परिणाम:

% gawk -f d.awk data 
A B C D E F 11 21 13 23 15 25 17 27 
A B C D E F 31 41 33 43 35 45 37 47 
A B C D E F 51 61 53 63 55 65 57 67 
A B C D E F 71 81 73 83 75 85 77 87 
2

पर्ल समाधान:

perl -ane ' 
    BEGIN { $, = " " } 
    if ($. % 2) { 
     @p = (@F[0..5], @F[grep 1-$_ % 2, 6 .. $#F]) 
    } else { 
     print @p[0..5], (map { $p[$_], $F[2 * $_ - 6] } 6 .. $#F), "\n" 
    }' 
+1

आह, पर्ल। आंखों के लिए हमेशा एक खुशी :) –

+2

@ टिचोड्रोमा: आपके समाधान के विपरीत, यह प्रश्न में निर्दिष्ट कॉलम के किसी भी संख्या के लिए काम करता है। – choroba

+0

सच है, लेकिन आवश्यक नहीं :) –

0

मैं इस के साथ आते हैं: की तरह चलाने के लिए

{ 
    if (NR % 2 == 1){ 
     for(i = 7; i <= NF; i += 2){ 
      array[i] = $i 
     } 
    } 
    else{ 
     printf "%s %s %s %s %s %s", $1, $2, $3, $4, $5, $6 
     for(i = 7; i <= NF; i += 2){ 
      printf " %s %s", array[i], $i 
     } 
     print "" 
    } 
} 

यह उदाहरण के लिए काम करता है किसी भी संख्या के साथ पोस्ट खोलना। इसके बारे में मेरी एकमात्र चिंता यह है कि मेरी वास्तविक डेटा फ़ाइलों में 2774 9 38 फ़ील्ड हैं, और चूंकि मैं एएफके के लिए नया हूं, मुझे नहीं पता कि यह करने का यह एक प्रभावी तरीका है या नहीं।

0
awk ' 
NR%2 { split($0,a); next } 
{ 
    for(i=7;i<NF;i+=2) { 
     $(i+1) = $i 
     $i = a[i] 
    } 
} 
1' file 

या आप किसी कैविएट्स के साथ एक "प्यारा" समाधान पसंद (लेकिन जो नमूना डेटा पोस्ट के साथ काम करेंगे) यदि:

awk ' 
!(NR%2) { printf fmt,$7,$9,$11,$13 } 
{ for (i=8;i<=NF;i+=2) $i="%s"; fmt=$0"\n" } 
' file 
0

यह आप के लिए काम कर सकते हैं (जीएनयू sed):

sed -r 's/(\s?\S+)\s\S+/\1/4g;h;s/.*//;N;s/(\s?\S+)\s\S+/\1/4g;H;g;s/^(.*)(.*\n)\n\1/\1\n\2/;h;s/[^\n]*\n//;:a;s/([^ \n]*)\n([^ \n]*)/\n\2 \1\n/g;s/\n \n?| \n/\n/g;/\n[^\n ]*$/!ba;y/\n/ /;H;x;s/\n.*\n//' file