मैं एक बैश शेल स्क्रिप्ट में 2 पैटर्न के बीच वर्णानुक्रमिक लाइनों को पसंद करता हूं।

निम्नलिखित इनपुट फ़ाइल को देखते हुए:

aaa
bbb
PATTERN1
foo
bar
baz
qux
PATTERN2
ccc
ddd

मुझे आउटपुट के रूप में उम्मीद है:

aaa
bbb
PATTERN1
bar
baz
foo
qux
PATTERN2
ccc
ddd

पसंदीदा उपकरण एक AWK "वन-लाइनर" है। सिड और अन्य समाधान भी स्वीकार किए जाते हैं। यदि स्पष्टीकरण शामिल है तो अच्छा होगा।

1
mike 27 नवम्बर 2015, 00:30

6 जवाब

सबसे बढ़िया उत्तर

यह asort() का उपयोग करने के लिए एक सही मामला है जीएनयू जाग में एक सरणी को सॉर्ट करने के लिए:

gawk '/PATTERN1/ {f=1; delete a}
      /PATTERN2/ {f=0; n=asort(a); for (i=1;i<=n;i++) print a[i]}
      !f
      f{a[$0]=$0}' file

यह एक समान तर्क का उपयोग करता है जैसे कि दो मार्कर पैटर्न के बीच की पंक्तियों का चयन कैसे करें जो कि जोड़ के साथ कई बार awk / sed हो सकती हैं बस यही है:

  • इस सीमा के बाहर प्रिंट की लाइनें
  • इस सीमा के भीतर स्टोर लाइनें
  • और जब सीमा खत्म हो जाती है, तो उन्हें छाँटते हैं।

विस्तृत विवरण:

  • /PATTERN1/ {f=1; delete a} PATTERN1 से मेल खाते हुए रेखा को खोजने पर, एक ध्वज को सेट करता है, और लाइनों की सरणी को साफ करता है।
  • /PATTERN2/ {f=0; n=asort(a); for (i=1;i<=n;i++) print a[i]} PATTERN2 से मेल खाते हुए लाइन ढूंढते समय, ध्वज को सेट करें। इसके अलावा, श्रेणी में सभी पंक्तियों वाले सरणी a[] को छांटें और उन्हें प्रिंट करें।
  • !f यदि झंडा बंद है (जो कि सीमा के बाहर है), तो सही के रूप में मूल्यांकन करें ताकि लाइन मुद्रित हो।
  • f{a[$0]=$0} यदि झंडा चालू है, तो लाइन को a[] सरणी में स्टोर करें, ताकि बाद में इसकी जानकारी का उपयोग किया जा सके।

परीक्षा

▶ gawk '/PATTERN1/ {f=1} /PATTERN2/ {f=0; n=asort(a); for (i=1;i<=n;i++) print a[i]} !f; f{a[$0]=$0}' FILE
aaa
bbb
PATTERN1
bar
baz
foo
qux
PATTERN2
ccc
ddd
7
Community 20 जून 2020, 09:12

आप sed और tail के साथ sed का उपयोग कर सकते हैं:

{
    sed '1,/^PATTERN1$/!d' FILE
    sed '/^PATTERN1$/,/^PATTERN2$/!d' FILE | head -n-1 | tail -n+2 | sort
    sed '/^PATTERN2$/,$!d' FILE
} > output

पहली पंक्ति पहली पंक्ति से PATTERN1 तक सब कुछ प्रिंट करती है।

दूसरी पंक्ति PATTERN1 और PATTERN2 के बीच की रेखाओं को लेती है, अंतिम और पहली पंक्ति को हटाती है, और शेष रेखाओं को क्रमबद्ध करती है।

तीसरी पंक्ति फ़ाइल के अंत में PATTERN2 से सब कुछ प्रिंट करती है।

4
Alex Harvey 5 अप्रैल 2019, 09:30

अधिक जटिल, लेकिन बहुत सारी लाइनों के भंडारण के मेमोरी लोड को कम कर सकता है (आपकी cfg फ़ाइल को इस बात के लिए बहुत बड़ा होना होगा, लेकिन फिर भी ...)। GNU awk और एक प्रकार के कॉपीप्रेशन का उपयोग करना:

gawk -v p=1 '
    /^PATTERN2/ {          # when we we see the 2nd marker:

        # close the "write" end of the pipe to sort. Then sort will know it
        # has all the data and it can begin sorting
        close("sort", "to");

        # then sort will print out the sorted results, so read and print that
        while (("sort" |& getline line) >0) print line 

        # and turn the boolean back to true
        p=1
    }
    p  {print}             # if p is true, print the line
    !p {print |& "sort"}   # if p is false, send the line to `sort`
    /^PATTERN1/ {p=0}      # when we see the first marker, turn off printing
' FILE
3
Alex Harvey 5 अप्रैल 2019, 09:27

यह थोड़ा अपरंपरागत है लेकिन विम का उपयोग कर रहा है:

vim -c 'exe "normal /PATTERN1\<cr>jV/PATTERN2\<cr>k: ! sort\<cr>" | wq!' FILE

जहाँ \<cr> एक गाड़ी वापसी है, CTRL - v फिर CTRL M के रूप में दर्ज किया गया है।

आगे की व्याख्या:

  • विम सामान्य मोड का उपयोग करना,
  • /PATTERN1\<cr> - पहले पैटर्न की खोज करें
  • j - अगली पंक्ति पर जाएं
  • V - दृश्य मोड दर्ज करें
  • /PATTERN2\<cr> - दूसरे पैटर्न की खोज करें
  • k - एक पंक्ति पर वापस जाएं
  • : ! sort\<cr> - आपके द्वारा चयनित दृश्य पाठ को क्रमबद्ध करें
  • wq! - सहेजें और बाहर निकलें
2
Alex Harvey 9 अप्रैल 2019, 14:14

जीएनयू sed का उपयोग करते हुए @choroba द्वारा प्रस्तावित समाधान की पंक्तियों के साथ, (Q कमांड पर निर्भर करता है):

{
  sed -n '1,/PATTERN1/p' FILE
  sed   '1,/PATTERN1/d; /PATTERN2/Q' FILE | sort
  sed -n '/PATTERN2/,$p' FILE
}

स्पष्टीकरण:

  • '1,/PATTERN1/p' और /PATTERN2/,$p क्रमशः p का उपयोग रेंज 1 से / PATTERN1 / समावेशी और ($ फ़ाइल के अंत में है) में एक रेखा प्रिंट करता है।
  • -n का उपयोग सभी लाइनों को प्रिंट करने के डिफ़ॉल्ट व्यवहार को अक्षम करता है। p के संयोजन में उपयोगी।
  • मध्य रेखा में, पहली पंक्ति मिलान / PATTERN2 / पर {1 X0}} कमांड का उपयोग 1 से / PATTERN1 / और Q (मुद्रण के बिना छोड़ना, GNU sed केवल) के लिए लाइनों को हटाने के लिए किया जाता है। इन लाइनों को क्रमबद्ध किया जाना है, और इस प्रकार sort में फीड किया जाता है।
0
Alex Harvey 5 अप्रैल 2019, 11:03

स्पष्ट रूप से यह GNU AWK समाधान से नीच है, लेकिन सभी एक ही, यह एक GNU sed समाधान है:

sed '
/PATTERN1/,/PATTERN2/ {
  /PATTERN1/b    # branch/break if /PATTERN1/. This line is printed
  /PATTERN2/ {   # if /PATTERN2/,
    x                    # swap hold and pattern spaces
    s/^\n//              # delete the leading newline. The first H puts it there
    s/.*/sort <<< "&"/e  # sort the pattern space by calling Unix sort
    p                    # print the sorted pattern space
    x                    # swap hold and pattern space again to retrieve PATTERN2
    p                    # print it also
  }
  H   # Append the pattern space to the hold space
  d   # delete this line for now - it will be printed in the block above
}
' FILE

ध्यान दें कि मैं e कमांड, एक GNU एक्सटेंशन।

परिक्षण:

▶ gsed '
/PATTERN1/,/PATTERN2/ {
  /PATTERN1/b
  /PATTERN2/ {
    x
    s/^\n//; s/.*/sort <<< "&"/ep
    x
    p
  }
  H
  d
}
' FILE
aaa
bbb
PATTERN1
bar
baz
foo
qux
PATTERN2
ccc
ddd
0
Alex Harvey 22 अप्रैल 2019, 06:36