एक पैटर्न के बाद नहीं लाइनों के लिए grep

Aug 17 2020

मैं एक विशिष्ट पैटर्न के बाद नहीं होने वाली फ़ाइल की सभी पंक्तियों को खोजने की कोशिश कर रहा हूं।

कुछ समय के लिए मेरे पास historyजीएनयू bash(संस्करण 4 और 5) का उपयोग करने के साथ एक मुद्दा था जहां कमांड डुप्लिकेट में दिखाई देते थे। मैंने माना कि यह इस तथ्य के कारण था कि मेरे .bashrcपास निम्नलिखित पंक्ति थी:

 PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"

और जब से मैं टर्मिनल मल्टीप्लेक्सर्स ( screenऔर / या tmux) का उपयोग कर रहा हूं , उपर्युक्त आदेश कई बार निष्पादित हो जाता है (इसलिए echo $PROMPT_COMMANDपरिणाम होता हैhistory -a; history -n; history -a; history -n;

कुछ स्थितियों में (विशेषकर जब विभिन्न पैन / खिड़कियों / फ़्रेमों / बफ़रों पर शंक्वाकार रूप से सामान करते हुए) अंतिम कमांड जो मैंने दर्ज की थी वह दो बार या इससे भी अधिक बार मेरे पास संग्रहीत की गई थी ~/.bash_history। इसके कारण निम्न की तरह प्रविष्टियाँ हुईं:

#1596110297
yadm list -a | xargs -t ls -l
yadm list -a | xargs -t ls -l

कहने की जरूरत नहीं है, यह बहुत कष्टप्रद है। मैं सिर्फ (उम्मीद है) history-issue (कमांड को बदलकर ) के लिए एक सुधार पाया गया, PROMPT_COMMAND="history -a; history -nलेकिन सुधार: इस में डुप्लिकेट प्रविष्टियों के साथ समस्या हल नहीं हुई history

अब मैं डुप्लिकेट प्रविष्टियों से छुटकारा पाना चाहूंगा।

इसलिए मैं वर्तमान में लाइनों के साथ शुरू होने वाली रेखाओं #और उसके बाद एक पंक्ति को छोड़कर सब कुछ चिह्नित करने के लिए एक नियमित अभिव्यक्ति खोजने की कोशिश कर रहा हूं । मेरा पहला विचार गठबंधन grep -v(चयन को पलटना) और grep -A 1(मिलान पैटर्न के बाद अतिरिक्त एक पंक्ति प्राप्त करना) था। परंतु

grep -v "^#" -A 1 ~/.bash_history

जिस परिणाम की मुझे उम्मीद थी, वह नहीं मिला।

इसलिए मेरा प्रश्न: क्या किसी को इस बात का अच्छा विचार है कि उस प्रयोग को कैसे किया जाए grep? यदि नहीं: कैसे मैं अन्य उपकरणों के साथ इस हासिल कर ( sed, awk, ...)?

जवाब

ilkkachu Aug 17 2020 at 03:48

जहां तक ​​मैं समझता हूं grep -v "^#" -A 1कि उन पंक्तियों को प्रिंट करना है जो हैश साइन से शुरू नहीं होते हैं, और प्रत्येक के बाद एक लाइन। लेकिन नहीं है आप विपरीत, लाइनों है कि प्रिंट चाहते हैं एक हैश हस्ताक्षर के साथ शुरू, और एक के बाद एक लाइन?

एक परीक्षण फ़ाइल दी:

#123
echo this
echo this
#456
echo that
echo that
echo that
#789
echo third

grep -A1 ^# history.txt |grep -vxFe -- प्रिंट:

#123
echo this
#456
echo that
#789
echo third

दूसरा grepसमूह विभाजक grep -Aप्रिंट से छुटकारा पाने के लिए है ।

वैकल्पिक रूप uniq history.txtसे लगातार समान लाइनों के प्रत्येक सेट को प्रिंट करने के लिए काम करना चाहिए।

jubilatious1 Aug 17 2020 at 18:40

राकु का उपयोग करना (née Perl6)

यह "फ्लिप-फ्लॉप" ऑपरेटर के लिए एक नौकरी की तरह लगता है, कई स्क्रिप्टिंग भाषाओं में उपलब्ध है। नीचे Raku प्रोग्रामिंग भाषा (पहले Perl6 के रूप में जाना जाता है) का उपयोग कर एक जवाब है। पहले एक अधिक व्यापक परीक्षण फ़ाइल बनाकर प्रारंभ करें:

$ cat repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
B_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
D_yadm list -a | xargs -t ls -l
E_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
G_yadm list -a | xargs -t ls -l
H_yadm list -a | xargs -t ls -l
I_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

अब एक लाइनर के लिए राकू के fffफ्लिप-फ्लॉप ऑपरेटर का उपयोग किया जाता है , जो "सेड-लाइक" व्यवहार को लागू करता है। कब्जा उन लाइनों के लिए चालू होता है जहां पहला रेगेक्स देखता है (शुरुआत के समय ^^) एक शाब्दिक "#" वर्ण। एक बार, कैप्चर पहले रेगेक्स को अनदेखा करता है और दूसरी रीगेक्स के खिलाफ मूल्यांकन करता है, जब वह गायब होने वाली लाइनों के खिलाफ एक मैच पाता है, तो ऑफ को बंद कर देता है (शुरुआत में लाइन ^^) "#" चरित्र। 'नेगेटिव' रेगेक्स का उपयोग करते हुए नीचे दिए गए कोड में लागू किया गया है <-[#]>, जो कि एक नकारात्मक "एनुमरेटेड कैरेक्टर क्लास" और राकु भाषा की एक वास्तविक विशेषता है:

$ raku -ne '.put if /^^ "#" / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

वास्तव में, पहला रेक्सैक्स ( fffइन्फिक्स ऑपरेटर के बाईं ओर ) का उपयोग करके लिखा जा सकता है <+[#]>, जो एक अधिक समानांतर निर्माण के लिए एक सकारात्मक "एनुमरेटेड कैरेक्टर क्लास" है:

$ raku -ne '.put if /^^ <+[#]> / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

इसके अलावा, यह मुझे लगता है कि आप अपने regex में सुधार के लिए मैच शुरू करने की मांग कर सकते हैं या एक से अधिक अंक "#" के खिलाफ एक या एक से अधिक अंक, यानी <digit>+नीचे देख सकते हैं:

$ raku -ne '.put if /^^ <+[#]> <digit>+ / fff /^^ <-[#]> <-digit>+ /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

[ऊपर दिए गए सभी कोड B, D, E, G, H, और I से शुरू होने वाली डुप्लिकेट की गई लाइनों को हटा देते हैं। मैंने केवल देखा कि दो लगातार लक्ष्य रेखाएं हैं जैसे "# 1596110297" आपके आउटपुट में दिखाई देगा, लेकिन यह स्पष्ट नहीं है मुझे अगर आपकी इनपुट फ़ाइल में ऐसी लगातार लाइनें होंगी]।

https://raku.org/