grep สำหรับเส้นที่ไม่อยู่หลังรูปแบบ

Aug 17 2020

ฉันกำลังพยายามค้นหาทุกบรรทัดของไฟล์ที่ไม่ได้อยู่หลังรูปแบบเฉพาะ

ในบางครั้งฉันมีปัญหากับการhistoryใช้ GNU 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

ใช้ Raku (née Perl6)

ดูเหมือนจะเป็นงานสำหรับโอเปอเรเตอร์ "flip-flop" ซึ่งมีให้บริการในภาษาสคริปต์หลายภาษา ด้านล่างนี้เป็นคำตอบโดยใช้ภาษาโปรแกรม 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 ซึ่งใช้พฤติกรรมที่ "เหมือน sed" การจับจะเปิดสำหรับบรรทัดที่ regex แรกเห็น (ที่จุดเริ่มต้นของบรรทัด^^) อักขระ "#" ตามตัวอักษร เมื่อเปิดแล้วการจับจะไม่สนใจ regex แรกและจะประเมินเทียบกับ regex ที่สองโดยจะปิดเมื่อพบว่าตรงกับบรรทัดที่ขาดหายไป (ที่จุดเริ่มต้นของบรรทัด^^) เป็นอักขระ "#" regex 'negative' ถูกนำไปใช้ในโค้ดด้านล่างโดยใช้<-[#]>ซึ่งเป็น "Enumerated Character Class" เชิงลบและคุณลักษณะที่แท้จริงของภาษา Raku:

$ 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 แรก (ทางด้านซ้ายของตัวfffดำเนินการ infix) สามารถเขียนได้โดยใช้<+[#]>ซึ่งเป็น "Enumerated Character Class" ที่เป็นบวกสำหรับการสร้างแบบขนานมากขึ้น:

$ 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/