จะค้นหาไฟล์ที่มีสองสายรวมกันใน Linux ได้อย่างไร?


11

ฉันต้องการที่จะหาไฟล์ที่มีสองสายร่วมกันเช่นไฟล์มีทั้งและstring1string2

ฉันต้องการเส้นทางแบบเต็มของไฟล์ที่ส่งออก ฉันไม่ต้องการเห็นคำเตือน "การปฏิเสธสิทธิ์"

คำตอบ:


15
grep -l string2 `grep -l string1 /path/*`

ซึ่งเหมือนกับ

grep -l string2 $(grep -l string1 /path/*)

แก้ไข: นี่คือเหตุผลที่grep string1 /path/* | grep string2ไม่ได้ทำในสิ่งที่ฉันคิดว่า alwbtc ต้องการ

$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$

ไม่พบอะไรเลย แต่ไฟล์ b มีทั้งสองสตริง

นี่คือสิ่งที่ฉันคิดว่า alwbtc ต้องการ

$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b

1
นี่เป็นทางออกที่เรียบร้อยและมีประโยชน์มากกว่าของฉัน สำหรับผู้ที่ต้องการทราบว่าเกิดอะไรขึ้นที่นี่ (เอาฉันไปคิดดู) เขาใช้-lตัวเลือกเพื่อส่งคืนชื่อไฟล์แทนที่จะเป็นบรรทัด จากนั้นเขาก็ใช้เครื่องหมายดอลลาร์หรือเครื่องหมายคำพูดด้านหลังเพื่อส่งผ่านรายการนั้นเป็นFILEอาร์กิวเมนต์ใน grep ตัวที่สอง วิธีนี้ช่วยให้ grep ตัวที่สองสามารถค้นหาไฟล์ทั้งหมดที่พบแทนแต่ละบรรทัดเช่นเดียวกับในโซลูชันของฉัน
embedded.kyle

คุณไม่ได้รับ-lตัวเลือกสำหรับทั้งสองคำสั่งให้ถือว่าเท่ากัน
pong

2

ท่อหนึ่งgrepเข้าด้วยกัน:

grep "string1" /path/to/files/* | grep "string2"


5
หากทั้งสองสายอยู่ในบรรทัดที่แตกต่างกันในไฟล์นี้จะไม่ทำงาน
RedGrittyBrick

1
ฉันไม่ทราบว่ามีข้อกำหนดสำหรับพวกเขาที่จะอยู่ในบรรทัดเดียวกัน @RedGrittyBrick
slhck

@slhck: ฉันได้อัปเดตคำตอบของฉันเพื่อแสดงสิ่งที่ฉันคิดว่า alwbtc ต้องการและทำไมคำตอบนี้ไม่ทำเช่นนั้น แน่นอนฉันอาจเข้าใจผิดในสิ่งที่ alwbtc ต้องการและฝังตัวไคล์อาจจะเข้าใจถูกต้อง - ฉันสงสัยว่าไม่ได้
RedGrittyBrick

1

ที่นี่เทียบเท่า คำสั่งให้คำตอบของ RedGrittyBrick :

ack string2 $(ack string1 -l)

ทำงานในลักษณะเดียวกัน (ยกเว้นackโดยค่าเริ่มต้นค้นหาไดเรกทอรีปัจจุบันซ้ำ) เนื้อหาภายในการ$()ค้นหาstring1แต่-lส่งออกเฉพาะชื่อไฟล์ที่พบสตริงนั้น พวกเขาจะถูกส่งผ่านเป็นข้อโต้แย้งในคำสั่งด้านนอกซึ่งหมายถึงการstring2ค้นหาภายในรายการของไฟล์เหล่านั้นเท่านั้น


0
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)

หรือน้อยกว่าซ้ำซ้อน:

search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)

สิ่งนี้จะทำงานหากสตริงอยู่ในบรรทัดที่แตกต่างกันของไฟล์เดียวกันและจะหลีกเลี่ยงผลบวกปลอมหากชื่อไฟล์มีหนึ่งในสตริง


0

หากต้องการอธิบายรายละเอียดเกี่ยวกับโซลูชันของ @ RedGrittyBrick ซึ่งมีข้อบกพร่องเมื่อรันคำสั่งแบบไม่ต้องใส่ข้อมูลบวกเพื่อระงับเอาต์พุตข้อผิดพลาดตามที่ต้องการและเพื่อค้นหาไฟล์แบบเรียกซ้ำคุณอาจพิจารณา

grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)

-sตัวเลือกจะระงับ
-rตัวเลือกข้อความผิดพลาดช่วยให้การค้นหาสตริงในไดเรกทอรีที่ซ้อนกันโดยพลการ
!รวมกับ&& echo /dev/nullการรับประกันว่าคำสั่งจะไม่วางสาย มิฉะนั้นหากinner grepไฟล์ไม่พบไฟล์ใด ๆ มันจะไม่แสดงผลใด ๆ ดังนั้นไฟล์outer grepจะรอให้อินพุตทำการค้นหาโดยไม่มีกำหนด โซลูชันนี้ให้ผลลัพธ์/dev/nullในกรณีเหล่านี้ดังนั้นouter grepจะค้นหาSTRING1ใน/dev/nullตำแหน่งที่ไม่ควรค้นหาสิ่งใด


0

ฉันกำลังมองหาวิธีที่สามารถขยายได้เพื่อทำสายอักขระ2 ตัวขึ้นไปและเกิดขึ้นกับสิ่งนี้:

grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3

grep แรกจะค้นหาชื่อไฟล์ซ้ำstring1ภายในpath-to-files

ผลที่จะได้เข้าไปประปาxargsซึ่งจะทำงานอย่างใดอย่างหนึ่งหรือ grep string2เพิ่มเติมคำสั่งเกี่ยวกับไฟล์เหล่านั้น

ผลลัพธ์จะถูกไพพ์ไปยังxargsคำสั่งอื่นสำหรับstring3- เหมือนกับการxargsโทรครั้งแรกแต่ค้นหาสตริงอื่น

การใช้xargsจะหลีกเลี่ยงปัญหาที่มีผลลัพธ์จำนวนมากที่บรรทัดคำสั่งผลลัพธ์จากการใช้เครื่องหมายขีดหลังยาวเกินไป

เพื่อหลีกเลี่ยงคำเตือนเราสามารถเปลี่ยนเส้นทางstderrไปที่/dev/null:

grep -rl string1 path-to-files  2>/dev/null | xargs grep -l string2

ไม่จำเป็นสำหรับการเรียก grep ครั้งต่อไปเนื่องจากstring1พบในไฟล์แล้วดังนั้นการอนุญาตจึงเป็นสิ่งที่ดี

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