พิมพ์รูปแบบที่ไม่ตรงกันโดยใช้ grep พร้อมรูปแบบจากไฟล์


15

patterns.txt:

"BananaOpinion"
"ExitWarning"
"SomeMessage"
"Help"
"Introduction"
"MessageToUser"

strings.xml

<string name="Introduction">One day there was an apple that went to the market.</string>
<string name="BananaOpinion">Bananas are great!</string>
<string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>

ผลลัพธ์ที่คาดหวัง:

"ExitWarning"
"SomeMessage"
"Help" 

ฉันจะพิมพ์คำศัพท์patterns.txtที่ไม่พบได้Strings.xmlอย่างไร ฉันสามารถพิมพ์ตรง / ตรงกันสายในStrings.xmlแต่ฉันจะพิมพ์เปรียบรูปแบบ ? ฉันใช้ ggrep (GNU grep) รุ่น 2.21 แต่เปิดให้ใช้เครื่องมืออื่น ๆ ขออภัยหากนี่เป็นคำถามซ้ำซ้อนกับคำถามอื่นที่ฉันไม่สามารถหาได้

คำตอบ:


25

คุณสามารถใช้grep -oเพื่อพิมพ์เฉพาะส่วนที่จับคู่และใช้ผลลัพธ์เป็นรูปแบบสำหรับวินาทีgrep -vในpatterns.txtไฟล์ต้นฉบับ:

grep -oFf patterns.txt Strings.xml | grep -vFf - patterns.txt

แม้ว่าในกรณีนี้คุณสามารถใช้join+ sort:

join -t\" -v1 -j2 -o 1.1 1.2 1.3 <(sort -t\" -k2 patterns.txt) <(sort -t\" -k2 strings.xml)

นี่เป็นสมาร์ทที่สวยงามมาก!
XXL

หากคุณมีไฟล์อินพุตหลายไฟล์ (เช่นStrings1.xmlและStrings2.xml) คุณจะต้อง-hตั้งค่าสถานะบน grep แรก
jayhendren

@ jayhendren - ใช่ แต่ไม่ใช่ทุกคนgrepที่สนับสนุนตัวเลือกนั้น หากคุณมีแฟ้มใส่หลายผมไม่เห็นเหตุผลที่คุณไม่สามารถทำได้เพียงแค่พวกเขาทั้งหมดและท่อผลให้cat grep
don_crissti

5

แนวทางที่ดีที่สุดน่าจะเป็นสิ่งที่ @don_crissti แนะนำดังนั้นนี่คือความแตกต่างของธีมเดียวกัน:

$ grep -vf <(grep -Po 'name=\K.+?"' Strings.xml) patterns.txt
"ExitWarning"
"SomeMessage"
"Help"

สิ่งนี้เป็นสิ่งที่ตรงกันข้ามกับแนวทางของ @ don_crissti มันใช้ grep กับ Perl Compatible Regular Expressions ( -P) และ-oสวิตช์เพื่อพิมพ์เฉพาะส่วนที่ตรงกันของบรรทัด จากนั้น regex จะค้นหาname=และทิ้งมัน ( \K) จากนั้นค้นหาอักขระหนึ่งตัวหรือมากกว่านั้นจนกระทั่งตัวแรก"( .+?") ผลลัพธ์นี้ในรายการของรูปแบบที่มีอยู่ในString.txtไฟล์ซึ่งจะถูกส่งผ่านเป็นอินพุตไปยัง grep ย้อนกลับ ( grep -v) โดยใช้การทดแทนกระบวนการ ( <(command))


2

ฉันจะใช้cutอาจจะ นั่นคือถ้าตามที่ปรากฏคุณจะรู้ว่าจะคาดหวังว่าสตริงที่ยกมาที่คุณกำลังมองหา

ถ้าฉันทำ:

{   cut  -sd\" -f2 |
    grep -vFf- pat
}   <<\IN
#   <string name="Introduction">One day there was an apple that went to the market.</string>
#   <string name="BananaOpinion">Bananas are great!</string>
#   <string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>
IN

... หลังจากบันทึกสำเนาตัวอย่างของคุณเองpatterns.txtในpatและเรียกใช้คำสั่งข้างต้นผลลัพธ์คือ:

"ExitWarning"
"SomeMessage"
"Help"

cutพิมพ์ที่ stdout แค่สอง"อ้างดับเบิล-delimited -field สำหรับแต่ละเส้นคั่นจับคู่เข้าและ-suppresses คนอื่น ๆ ทั้งหมด

สิ่งที่cutพิมพ์จริงgrepคือ:

Introduction
BananaOpinion
MessageToUser

grepค้นหาตัวถูกดำเนินการไฟล์ที่ระบุชื่อเพื่อหาบรรทัดที่-vไม่ตรงกับ-Fสตริง ixed ใน-รูปแบบ stdin -file

หากคุณสามารถพึ่งพาสอง"ฟิลด์ -delimited เป็นหนึ่งเพื่อให้ตรงแล้วแน่นอนมันจะเพิ่มประสิทธิภาพมากกว่าgrep -Pโหมด Erl โดยเพียงแค่การจับคู่-Fสตริงคงที่และบางส่วนเพียงเล็ก ๆ ของพวกเขาเพราะcutไม่ยกของหนัก - และมันไม่ได้อย่างรวดเร็ว


1
for p in $(cat patterns.txt); do if ! grep $p strings.xml &>/dev/null; then echo $p; fi; done

มันง่ายที่จะเข้าใจ แต่มีการหยุดทำงานของการวางไข่ของกระบวนการ grep หลายกระบวนการสำหรับแต่ละบรรทัดใน pattern.txt


0

อีกวิธีหนึ่งคือการใส่ patterns.txt และ Strings.xml ลงในรายการเดียวและค้นหาแถวที่ไม่ซ้ำกัน

cat patterns.txt Strings.xml | grep -oFf patterns.txt | sort | uniq -u

คำอธิบาย:

cat patterns.txt Strings.xmlใส่ทุกอย่างไว้ในรายการเดียว grep -oFf patterns.txtกำจัดขยะในแต่ละบรรทัด sortอธิบายตนเอง จัดเรียงทุกบรรทัด uniq -uพิมพ์บรรทัดที่ไม่ซ้ำกันเท่านั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.