วิธีไพพ์รายชื่อไฟล์ที่ส่งคืนโดยคำสั่ง find เพื่อ cat เพื่อดูไฟล์ทั้งหมด


204

ฉันทำfindแล้วได้รับรายชื่อไฟล์ ฉันจะไพพ์ไปยังยูทิลิตี้อื่นเช่นcat(เพื่อให้ cat แสดงเนื้อหาของไฟล์เหล่านั้นทั้งหมด) และโดยทั่วไปจำเป็นต้องมีgrepบางอย่างจากไฟล์เหล่านี้

คำตอบ:


340
  1. การไปยังกระบวนการอื่น (แม้ว่าสิ่งนี้จะไม่สำเร็จในสิ่งที่คุณพูดว่าคุณพยายามจะทำ):

    command1 | command2
    

    สิ่งนี้จะส่งเอาต์พุตของ command1 เป็นอินพุตของ command2

  2. -execบนfind(สิ่งนี้จะทำสิ่งที่คุณต้องการจะทำ - แต่เฉพาะเจาะจงfind)

    find . -name '*.foo' -exec cat {} \;
    

    (ทุกสิ่งระหว่างfindและ-execเป็นเพรดิเคตการค้นหาที่คุณใช้อยู่แล้ว {}จะแทนที่ไฟล์เฉพาะที่คุณพบในคำสั่ง ( cat {}ในกรณีนี้); \;คือการสิ้นสุด-execคำสั่ง)

  3. ส่งเอาต์พุตของหนึ่งกระบวนการเป็นอาร์กิวเมนต์บรรทัดคำสั่งไปยังกระบวนการอื่น

    command2 `command1`
    

    ตัวอย่างเช่น:

    cat `find . -name '*.foo' -print`
    

    (หมายเหตุเหล่านี้คือ BACK-QUOTES ไม่ใช่เครื่องหมายคำพูดปกติ (ใต้เครื่องหมายตัวหนอน ~ บนแป้นพิมพ์ของฉัน)) สิ่งนี้จะส่งเอาต์พุตของcommand1ไปcommand2เป็นอาร์กิวเมนต์บรรทัดคำสั่ง โปรดทราบว่าชื่อไฟล์ที่มีช่องว่าง (ขึ้นบรรทัดใหม่ ฯลฯ ) จะถูกแบ่งออกเป็นอาร์กิวเมนต์แยกต่างหาก


2
แมวfind -name '*.foo' -printทำงานได้ดีสำหรับฉัน ... ขอบคุณ
Devang Kamdar

Backquotes ใช้งานได้ดีและมีความเป็นทั่วไปมากขึ้นคุณสามารถใช้สิ่งนี้เพื่อจัดทำรายการไฟล์จากไฟล์ได้เช่นกัน
Hazok

11
โปรดทราบว่าเวอร์ชันที่ทันสมัยของfindอนุญาตให้คุณเขียน: find . -name '*.foo' -exec cat {} +โดยที่ตัว+บ่งชี้ที่findควรจัดกลุ่มชื่อไฟล์ให้มากที่สุดเท่าที่สะดวกในการเรียกใช้คำสั่งเดียว สิ่งนี้มีประโยชน์มาก (มันเกี่ยวข้องกับช่องว่าง ฯลฯ ในชื่อไฟล์โดยไม่ต้องหันไปใช้-print0และxargs -0)
Jonathan Leffler

18
find . -name '*.foo' | xargs cat
Unmentioned

3
เพียงเพื่อเพิ่มคำตอบ @stewSquared s: ในการหาทุกบรรทัดในไฟล์ที่มีสตริงบางทำfind . -name '*.foo' | xargs cat | grep string
บิ๋ม

84

รุ่นทันสมัย

POSIX 2008 ได้เพิ่มตัว+ทำเครื่องหมายfindซึ่งหมายความว่าตอนนี้จะจัดกลุ่มไฟล์ให้มากที่สุดเท่าที่จะเป็นไปได้โดยอัตโนมัติในการดำเนินการคำสั่งเดียวซึ่งคล้ายกับที่xargsทำ แต่มีข้อดีหลายประการ:

  1. คุณไม่ต้องกังวลกับอักขระแปลก ๆ ในชื่อไฟล์
  2. คุณไม่ต้องกังวลเกี่ยวกับคำสั่งที่ถูกเรียกด้วยชื่อไฟล์ศูนย์

ปัญหาชื่อไฟล์เป็นปัญหาxargsโดยไม่มี-0ตัวเลือกและปัญหา 'เรียกใช้แม้แต่ชื่อไฟล์ศูนย์' เป็นปัญหาที่มีหรือไม่มี-0ตัวเลือก - แต่ GNU xargsมีตัวเลือก-rหรือ--no-run-if-emptyตัวเลือกเพื่อป้องกันไม่ให้เกิดขึ้น นอกจากนี้เอกสารนี้จะลดจำนวนกระบวนการไม่ใช่ว่าคุณมีแนวโน้มที่จะวัดความแตกต่างในประสิทธิภาพ ดังนั้นคุณสามารถเขียนได้อย่างสมเหตุสมผล:

find . -exec grep something {} +

รุ่นคลาสสิค

find . -print | xargs grep something

หากคุณอยู่ในลินุกซ์หรือมี GNU findและxargsคำสั่งแล้วใช้-print0ด้วยfindและ-0มีxargsการจับชื่อไฟล์ที่มีช่องว่างและตัวอักษรแปลกลูกอื่น ๆ

find . -print0 | xargs -0 grep something

การปรับแต่งผลลัพธ์จาก grep

หากคุณไม่ต้องการชื่อไฟล์ (เพียงแค่ข้อความ) ให้เพิ่มตัวเลือกที่เหมาะสมในgrep(โดยปกติจะ-hเป็นการระงับ 'ส่วนหัว') หากต้องการรับประกันชื่อไฟล์อย่างแท้จริงจะถูกพิมพ์โดยgrep(แม้ว่าจะพบไฟล์เดียวเท่านั้นหรือการร้องขอล่าสุดของgrepชื่อไฟล์ 1 ชื่อเท่านั้น) จากนั้นเพิ่มลง/dev/nullในxargsบรรทัดคำสั่งเพื่อให้มีชื่อไฟล์อย่างน้อยสองชื่อ


xargs grep somethingสำหรับผู้ที่สับสนเหมือนฉันทราบว่าวิธีการนี้เป็นครั้งแรกที่จะทำให้การส่งออกของทุกพบแล้วให้การส่งออกของ
Eric Hu

3
@EricHu: ฉันเห็นว่าคุณสับสน แต่ก็ไม่ได้ทำในสิ่งที่คุณพูดอย่างน้อยที่สุดก็ไม่ได้อยู่ในระบบที่ใช้ Unix การส่งออกของมีประปาเข้ามาตรฐานของfind โปรแกรมอ่านเข้ามาตรฐานของการแยกการป้อนข้อมูลที่พื้นที่สีขาว (ช่องว่างการขึ้นบรรทัดใหม่แท็บ ฯลฯ ) และผนวกจำนวนของคำสั่งและดำเนินการบรรทัดคำสั่ง จากนั้นดำเนินการอ่านอินพุตและเรียกใช้คำสั่งต่อไปจนกว่าจะหมดอินพุต รันคำสั่งได้บ่อยเท่าที่จำเป็นสำหรับอินพุตที่ได้รับ (จากในตัวอย่างนี้) xargsxargsgrep somethingxargsxargsgrepfind
Jonathan Leffler

ความผิดพลาดของฉันนี่คือการใช้ grep เพื่อค้นหาภายในแต่ละไฟล์ที่ตรงกัน ฉันแค่ต้องการกรองผลลัพธ์ของการค้นหาด้วย grep
Eric Hu

1
ข้อผิดพลาดไปที่ข้อผิดพลาดมาตรฐาน (file descriptor 2) ในคำสั่งที่ทำงานได้ดีทั้งหมด การเปลี่ยนเส้นทาง stderr เพื่อ/dev/nullลดข้อผิดพลาด
Jonathan Leffler

1
สิ่งนี้ยังมีประโยชน์ที่จะทำงานได้ดีขึ้นกับช่องว่างในเส้นทางของไฟล์ แม้แต่ 'sed'ing "" -> "\" แบ่งมันด้วย `แต่ด้วย xargs มันทำงานได้อย่างสมบูรณ์แบบ
JZL003

36

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

  1. วิธีที่ง่ายที่สุดคือใช้ backticks ( `):

    cat `find [whatever]`
    

    นี้จะใช้เวลาการส่งออกของและมีประสิทธิภาพวางมันลงบนบรรทัดคำสั่งของfind catวิธีนี้ใช้ไม่ได้ผลหากfindมีเอาต์พุตมากเกินไป (มากกว่าที่จะใส่ในบรรทัดคำสั่ง) หรือถ้าเอาต์พุตมีอักขระพิเศษ (เช่นช่องว่าง)

  2. ในเชลล์บางตัวรวมถึงbashหนึ่งสามารถใช้$()แทน backticks:

    cat $(find [whatever])
    

    นี่เป็นแบบพกพาน้อย แต่สามารถซ้อนได้ นอกเหนือจากนั้นมันก็มีข้อแม้เหมือนกันมากกับแบ็คคิก

  3. เนื่องจากการเรียกใช้คำสั่งอื่น ๆ เกี่ยวกับสิ่งที่พบเป็นการใช้โดยทั่วไปfindfind จึงมีการ-execดำเนินการที่เรียกใช้คำสั่งสำหรับแต่ละไฟล์ที่พบ:

    find [whatever] -exec cat {} \;
    

    The {}เป็นตัวยึดสำหรับชื่อไฟล์และ\;ทำเครื่องหมายจุดสิ้นสุดของคำสั่ง (เป็นไปได้ที่จะมีการดำเนินการอื่น ๆ หลังจาก-execนั้น)

    นี้จะทำงานcatครั้งเดียวสำหรับทุกไฟล์เดียวมากกว่าการทำงานเช่นเดียวของcatผ่านมันชื่อไฟล์หลายซึ่งอาจจะไม่มีประสิทธิภาพและไม่อาจมีพฤติกรรมที่คุณต้องการสำหรับคำสั่งบางอย่าง (แม้ว่ามันจะเป็นที่ดีสำหรับการcat) ไวยากรณ์ยังเป็นที่น่าอึดอัดใจในการพิมพ์ - คุณต้องหนีเครื่องหมายอัฒภาคเนื่องจากเครื่องหมายอัฒภาคเป็นพิเศษสำหรับเชลล์!

  4. บางรุ่นของfind(รุ่น GNU ที่สะดุดตาที่สุด) ให้คุณแทนที่;ด้วย+เพื่อใช้-execโหมดผนวกของเพื่อเรียกใช้อินสแตนซ์น้อยลงของcat:

    find [whatever] -exec cat {} +
    

    วิธีนี้จะส่งชื่อไฟล์หลาย ๆ ชื่อให้กับการเรียกใช้แต่ละครั้งcatซึ่งจะมีประสิทธิภาพมากขึ้น

    โปรดทราบว่านี่ไม่ใช่รับประกันว่าจะใช้การเรียกใช้ครั้งเดียวอย่างไรก็ตาม catถ้าบรรทัดคำสั่งจะยาวเกินไปแล้วข้อโต้แย้งที่มีการแพร่กระจายไปทั่วหลายสวดของ สำหรับcatสิ่งนี้อาจไม่ใช่เรื่องใหญ่ แต่สำหรับบางคำสั่งอื่น ๆ นี้อาจเปลี่ยนพฤติกรรมในรูปแบบที่ไม่พึงประสงค์ บนระบบ Linux ขีดจำกัดความยาวบรรทัดคำสั่งค่อนข้างใหญ่ดังนั้นการแบ่งการเรียกใช้หลายครั้งจึงค่อนข้างหายากเมื่อเทียบกับระบบปฏิบัติการอื่น ๆ

  5. วิธีการแบบคลาสสิก / พกพาคือการใช้ xargs :

    find [whatever] | xargs cat
    

    xargsรันคำสั่งที่ระบุ ( catในกรณีนี้) และเพิ่มอาร์กิวเมนต์ตามสิ่งที่อ่านจาก stdin เช่นเดียว-execกับ+สิ่งนี้จะแยกบรรทัดคำสั่งหากจำเป็น นั่นคือถ้าfindสร้างผลลัพธ์มากเกินไปมันจะทำงานcatหลายครั้ง ตามที่กล่าวไว้ในส่วนเกี่ยวกับ-execก่อนหน้านี้มีคำสั่งบางอย่างที่การแยกนี้อาจส่งผลให้เกิดพฤติกรรมที่แตกต่าง โปรดทราบว่าการใช้xargsสิ่งนี้มีปัญหากับช่องว่างในชื่อไฟล์เนื่องจากxargsใช้ช่องว่างเป็นตัวคั่น

  6. วิธีการที่แข็งแกร่งพกพาและมีประสิทธิภาพที่สุดก็ใช้เช่นกัน xargs :

    find [whatever] -print0 | xargs -0 cat
    

    -print0ธงบอกfindถึงการใช้\0null (ตัวอักษร) คั่นระหว่างชื่อไฟล์และ-0ธงบอกxargsที่คาดหวังเหล่านี้\0คั่น สิ่งนี้มีพฤติกรรมที่เหมือนกันกับวิธีการ-exec... +แต่สามารถพกพาได้มากกว่า (แต่น่าเสียดายยิ่งกว่า)


วิธีการ backtick นั้นยอดเยี่ยมเพราะมันใช้ได้กับคำสั่งอื่นเช่นlsกัน
Martin Braun

@ Martin Braun ใช้$()นอกจากนี้ยังทำงานร่วมกับคำสั่งอื่น ๆ find กว่า
Laurence Gonsalves

ขอบคุณที่รู้ฉันหยุดอ่านหลังจาก (1) เพราะมันตอบสนองความต้องการของฉันเนื่องจากฉันไม่ได้จัดการกับตัวละครพิเศษเช่นช่องว่างและเช่นนั้น
Martin Braun

9

เพื่อให้บรรลุนี้ (ใช้ทุบตี) ฉันจะทำดังนี้

cat $(find . -name '*.foo')

สิ่งนี้เรียกว่า "การทดแทนคำสั่ง" และจะตัดการป้อนบรรทัดตามค่าเริ่มต้นซึ่งเป็นวิธีที่ง่ายมาก!

ข่าวสารเพิ่มเติมได้ที่นี่


6

ฟังดูเหมือนงานสำหรับเชลล์สคริปต์สำหรับฉัน:

for file in 'find -name *.xml'
do
   grep 'hello' file
done

หรืออะไรทำนองนั้น


2
นี่เป็นคำตอบที่ถูกต้องแม้ว่าจะไม่เหมาะสมก็ตาม
Jonathan Leffler

1
... ใช่ แต่มันยอดเยี่ยมถ้าคุณต้องการไฟล์ขนาดใหญ่หนึ่งไฟล์ที่มีชื่อไฟล์เช่นกัน
ʍǝɥʇɐɯ

1
ฉันชอบสิ่งนี้ที่สุด บล็อกลูปแบบนี้จะเหลือที่ว่างให้ทำอย่างอื่น
kakyo

4

นี่คือวิธีค้นหาชื่อไฟล์ที่มีเนื้อหาบางอย่างที่ฉันสนใจเพียงแค่ bash line เดียวที่จัดการช่องว่างในชื่อไฟล์ได้ดี:

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done

3

ฉันใช้สิ่งนี้:

find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>

" -print0" อาร์กิวเมนต์สำหรับ "find" และ " -0" อาร์กิวเมนต์สำหรับ "xargs" จำเป็นต้องใช้เพื่อจัดการช่องว่างในพา ธ / ชื่อไฟล์อย่างถูกต้อง



2

นี่คือช็อตของฉันสำหรับใช้งานทั่วไป:

grep YOURSTRING `find .`

มันจะพิมพ์ชื่อไฟล์


2

ในทุบตีต่อไปนี้จะมีความเหมาะสม:

find /dir -type f -print0 | xargs -0i cat {} | grep whatever

การทำเช่นนี้จะค้นหาไฟล์ทั้งหมดใน/dirไดเรกทอรีและวางท่อชื่อไฟล์xargsอย่างปลอดภัยซึ่งจะขับอย่างปลอดภัยgrepซึ่งจะขับรถอย่างปลอดภัย

ข้ามxargsไม่ได้เป็นความคิดที่ดีถ้าคุณมีหลายพันคนของไฟล์ใน/dir; catจะแตกเนื่องจากมีรายการอาร์กิวเมนต์ยาวเกินไปxargsจะเรียงลำดับที่ออกมาทั้งหมดสำหรับคุณ

-print0อาร์กิวเมนต์findตาข่ายกับ-0อาร์กิวเมนต์xargsที่จะจัดการกับชื่อไฟล์ที่มีช่องว่างอย่างถูกต้อง -iอาร์กิวเมนต์xargsช่วยให้คุณสามารถใส่ชื่อไฟล์ที่จำเป็นต้องใช้ในcatบรรทัดคำสั่ง วงเล็บจะถูกแทนที่ด้วยประปาชื่อไฟล์ลงในคำสั่งจากcatfind



0

ใช้ggrep

ggrep -H -R -I "mysearchstring" *

เพื่อค้นหาไฟล์ในระบบยูนิกซ์ที่มีข้อความอยู่ในไดเรกทอรีปัจจุบันหรือไดเรกทอรีย่อย


0

สิ่งนี้จะพิมพ์ชื่อและเนื้อหาของไฟล์แบบเรียกซ้ำเท่านั้น

find . -type f -printf '\n\n%p:\n' -exec cat {} \;

แก้ไข (เวอร์ชั่นที่ปรับปรุงแล้ว): สิ่งนี้จะพิมพ์ชื่อและเนื้อหาของไฟล์ข้อความ (ascii) แบบเรียกซ้ำเท่านั้น ..

find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'

อีกหนึ่งความพยายาม

find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;

-1

คุณพยายามค้นหาข้อความในไฟล์หรือไม่? คุณสามารถใช้ grep สำหรับสิ่งนั้นได้ ...

grep searchterm *

-1

ในการแสดงรายการและดูเนื้อหาของไฟล์ abc.def ทั้งหมดบนเซิร์ฟเวอร์ในไดเรกทอรี / ghi และ / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;

หากต้องการแสดงรายการไฟล์ abc.def ที่มีรายการที่ถูกคอมเม้นต์และแสดงให้ดูรายการเหล่านั้นในไดเร็กทอรี / ghi และ / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.