ฉันทำfindแล้วได้รับรายชื่อไฟล์ ฉันจะไพพ์ไปยังยูทิลิตี้อื่นเช่นcat(เพื่อให้ cat แสดงเนื้อหาของไฟล์เหล่านั้นทั้งหมด) และโดยทั่วไปจำเป็นต้องมีgrepบางอย่างจากไฟล์เหล่านี้
ฉันทำfindแล้วได้รับรายชื่อไฟล์ ฉันจะไพพ์ไปยังยูทิลิตี้อื่นเช่นcat(เพื่อให้ cat แสดงเนื้อหาของไฟล์เหล่านั้นทั้งหมด) และโดยทั่วไปจำเป็นต้องมีgrepบางอย่างจากไฟล์เหล่านี้
คำตอบ:
การไปยังกระบวนการอื่น (แม้ว่าสิ่งนี้จะไม่สำเร็จในสิ่งที่คุณพูดว่าคุณพยายามจะทำ):
command1 | command2
สิ่งนี้จะส่งเอาต์พุตของ command1 เป็นอินพุตของ command2
-execบนfind(สิ่งนี้จะทำสิ่งที่คุณต้องการจะทำ - แต่เฉพาะเจาะจงfind)
find . -name '*.foo' -exec cat {} \;
(ทุกสิ่งระหว่างfindและ-execเป็นเพรดิเคตการค้นหาที่คุณใช้อยู่แล้ว {}จะแทนที่ไฟล์เฉพาะที่คุณพบในคำสั่ง ( cat {}ในกรณีนี้); \;คือการสิ้นสุด-execคำสั่ง)
ส่งเอาต์พุตของหนึ่งกระบวนการเป็นอาร์กิวเมนต์บรรทัดคำสั่งไปยังกระบวนการอื่น
command2 `command1`
ตัวอย่างเช่น:
cat `find . -name '*.foo' -print`
(หมายเหตุเหล่านี้คือ BACK-QUOTES ไม่ใช่เครื่องหมายคำพูดปกติ (ใต้เครื่องหมายตัวหนอน ~ บนแป้นพิมพ์ของฉัน)) สิ่งนี้จะส่งเอาต์พุตของcommand1ไปcommand2เป็นอาร์กิวเมนต์บรรทัดคำสั่ง โปรดทราบว่าชื่อไฟล์ที่มีช่องว่าง (ขึ้นบรรทัดใหม่ ฯลฯ ) จะถูกแบ่งออกเป็นอาร์กิวเมนต์แยกต่างหาก
findอนุญาตให้คุณเขียน: find . -name '*.foo' -exec cat {} +โดยที่ตัว+บ่งชี้ที่findควรจัดกลุ่มชื่อไฟล์ให้มากที่สุดเท่าที่สะดวกในการเรียกใช้คำสั่งเดียว สิ่งนี้มีประโยชน์มาก (มันเกี่ยวข้องกับช่องว่าง ฯลฯ ในชื่อไฟล์โดยไม่ต้องหันไปใช้-print0และxargs -0)
find . -name '*.foo' | xargs cat
find . -name '*.foo' | xargs cat | grep string
POSIX 2008 ได้เพิ่มตัว+ทำเครื่องหมายfindซึ่งหมายความว่าตอนนี้จะจัดกลุ่มไฟล์ให้มากที่สุดเท่าที่จะเป็นไปได้โดยอัตโนมัติในการดำเนินการคำสั่งเดียวซึ่งคล้ายกับที่xargsทำ แต่มีข้อดีหลายประการ:
ปัญหาชื่อไฟล์เป็นปัญหา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สำหรับผู้ที่สับสนเหมือนฉันทราบว่าวิธีการนี้เป็นครั้งแรกที่จะทำให้การส่งออกของทุกพบแล้วให้การส่งออกของ
find โปรแกรมอ่านเข้ามาตรฐานของการแยกการป้อนข้อมูลที่พื้นที่สีขาว (ช่องว่างการขึ้นบรรทัดใหม่แท็บ ฯลฯ ) และผนวกจำนวนของคำสั่งและดำเนินการบรรทัดคำสั่ง จากนั้นดำเนินการอ่านอินพุตและเรียกใช้คำสั่งต่อไปจนกว่าจะหมดอินพุต รันคำสั่งได้บ่อยเท่าที่จำเป็นสำหรับอินพุตที่ได้รับ (จากในตัวอย่างนี้) xargsxargsgrep somethingxargsxargsgrepfind
/dev/nullลดข้อผิดพลาด
มีไม่กี่วิธีที่จะผ่านรายการของไฟล์ที่ส่งกลับโดยมีfindคำสั่งไปยังcatคำสั่ง catแต่ในทางเทคนิคไม่ได้ทั้งหมดท่อใช้และไม่มีท่อจริงโดยตรงกับ
วิธีที่ง่ายที่สุดคือใช้ backticks ( `):
cat `find [whatever]`
นี้จะใช้เวลาการส่งออกของและมีประสิทธิภาพวางมันลงบนบรรทัดคำสั่งของfind catวิธีนี้ใช้ไม่ได้ผลหากfindมีเอาต์พุตมากเกินไป (มากกว่าที่จะใส่ในบรรทัดคำสั่ง) หรือถ้าเอาต์พุตมีอักขระพิเศษ (เช่นช่องว่าง)
ในเชลล์บางตัวรวมถึงbashหนึ่งสามารถใช้$()แทน backticks:
cat $(find [whatever])
นี่เป็นแบบพกพาน้อย แต่สามารถซ้อนได้ นอกเหนือจากนั้นมันก็มีข้อแม้เหมือนกันมากกับแบ็คคิก
เนื่องจากการเรียกใช้คำสั่งอื่น ๆ เกี่ยวกับสิ่งที่พบเป็นการใช้โดยทั่วไปfindfind จึงมีการ-execดำเนินการที่เรียกใช้คำสั่งสำหรับแต่ละไฟล์ที่พบ:
find [whatever] -exec cat {} \;
The {}เป็นตัวยึดสำหรับชื่อไฟล์และ\;ทำเครื่องหมายจุดสิ้นสุดของคำสั่ง (เป็นไปได้ที่จะมีการดำเนินการอื่น ๆ หลังจาก-execนั้น)
นี้จะทำงานcatครั้งเดียวสำหรับทุกไฟล์เดียวมากกว่าการทำงานเช่นเดียวของcatผ่านมันชื่อไฟล์หลายซึ่งอาจจะไม่มีประสิทธิภาพและไม่อาจมีพฤติกรรมที่คุณต้องการสำหรับคำสั่งบางอย่าง (แม้ว่ามันจะเป็นที่ดีสำหรับการcat) ไวยากรณ์ยังเป็นที่น่าอึดอัดใจในการพิมพ์ - คุณต้องหนีเครื่องหมายอัฒภาคเนื่องจากเครื่องหมายอัฒภาคเป็นพิเศษสำหรับเชลล์!
บางรุ่นของfind(รุ่น GNU ที่สะดุดตาที่สุด) ให้คุณแทนที่;ด้วย+เพื่อใช้-execโหมดผนวกของเพื่อเรียกใช้อินสแตนซ์น้อยลงของcat:
find [whatever] -exec cat {} +
วิธีนี้จะส่งชื่อไฟล์หลาย ๆ ชื่อให้กับการเรียกใช้แต่ละครั้งcatซึ่งจะมีประสิทธิภาพมากขึ้น
โปรดทราบว่านี่ไม่ใช่รับประกันว่าจะใช้การเรียกใช้ครั้งเดียวอย่างไรก็ตาม catถ้าบรรทัดคำสั่งจะยาวเกินไปแล้วข้อโต้แย้งที่มีการแพร่กระจายไปทั่วหลายสวดของ สำหรับcatสิ่งนี้อาจไม่ใช่เรื่องใหญ่ แต่สำหรับบางคำสั่งอื่น ๆ นี้อาจเปลี่ยนพฤติกรรมในรูปแบบที่ไม่พึงประสงค์ บนระบบ Linux ขีดจำกัดความยาวบรรทัดคำสั่งค่อนข้างใหญ่ดังนั้นการแบ่งการเรียกใช้หลายครั้งจึงค่อนข้างหายากเมื่อเทียบกับระบบปฏิบัติการอื่น ๆ
วิธีการแบบคลาสสิก / พกพาคือการใช้ xargs :
find [whatever] | xargs cat
xargsรันคำสั่งที่ระบุ ( catในกรณีนี้) และเพิ่มอาร์กิวเมนต์ตามสิ่งที่อ่านจาก stdin เช่นเดียว-execกับ+สิ่งนี้จะแยกบรรทัดคำสั่งหากจำเป็น นั่นคือถ้าfindสร้างผลลัพธ์มากเกินไปมันจะทำงานcatหลายครั้ง ตามที่กล่าวไว้ในส่วนเกี่ยวกับ-execก่อนหน้านี้มีคำสั่งบางอย่างที่การแยกนี้อาจส่งผลให้เกิดพฤติกรรมที่แตกต่าง โปรดทราบว่าการใช้xargsสิ่งนี้มีปัญหากับช่องว่างในชื่อไฟล์เนื่องจากxargsใช้ช่องว่างเป็นตัวคั่น
วิธีการที่แข็งแกร่งพกพาและมีประสิทธิภาพที่สุดก็ใช้เช่นกัน xargs :
find [whatever] -print0 | xargs -0 cat
-print0ธงบอกfindถึงการใช้\0null (ตัวอักษร) คั่นระหว่างชื่อไฟล์และ-0ธงบอกxargsที่คาดหวังเหล่านี้\0คั่น สิ่งนี้มีพฤติกรรมที่เหมือนกันกับวิธีการ-exec... +แต่สามารถพกพาได้มากกว่า (แต่น่าเสียดายยิ่งกว่า)
lsกัน
$()นอกจากนี้ยังทำงานร่วมกับคำสั่งอื่น ๆ find กว่า
เพื่อให้บรรลุนี้ (ใช้ทุบตี) ฉันจะทำดังนี้
cat $(find . -name '*.foo')
สิ่งนี้เรียกว่า "การทดแทนคำสั่ง" และจะตัดการป้อนบรรทัดตามค่าเริ่มต้นซึ่งเป็นวิธีที่ง่ายมาก!
ข่าวสารเพิ่มเติมได้ที่นี่
ฟังดูเหมือนงานสำหรับเชลล์สคริปต์สำหรับฉัน:
for file in 'find -name *.xml'
do
grep 'hello' file
done
หรืออะไรทำนองนั้น
นี่คือวิธีค้นหาชื่อไฟล์ที่มีเนื้อหาบางอย่างที่ฉันสนใจเพียงแค่ bash line เดียวที่จัดการช่องว่างในชื่อไฟล์ได้ดี:
find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
ฉันใช้สิ่งนี้:
find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>
" -print0" อาร์กิวเมนต์สำหรับ "find" และ " -0" อาร์กิวเมนต์สำหรับ "xargs" จำเป็นต้องใช้เพื่อจัดการช่องว่างในพา ธ / ชื่อไฟล์อย่างถูกต้อง
คำสั่ง find มีอาร์กิวเมนต์ -exec ที่คุณสามารถใช้สำหรับสิ่งนี้คุณสามารถใช้ grep โดยตรงได้
ตัวอย่างเช่น ( จากที่นี่ตัวอย่างที่ดีอื่น ๆ ในหน้านี้ ):
find . -exec grep "www.athabasca" '{}' \; -print
นี่คือช็อตของฉันสำหรับใช้งานทั่วไป:
grep YOURSTRING `find .`
มันจะพิมพ์ชื่อไฟล์
ในทุบตีต่อไปนี้จะมีความเหมาะสม:
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
มันใช้งานได้สำหรับฉัน
find _CACHE_* | while read line; do
cat "$line" | grep "something"
done
ggrep -H -R -I "mysearchstring" *
เพื่อค้นหาไฟล์ในระบบยูนิกซ์ที่มีข้อความอยู่ในไดเรกทอรีปัจจุบันหรือไดเรกทอรีย่อย
สิ่งนี้จะพิมพ์ชื่อและเนื้อหาของไฟล์แบบเรียกซ้ำเท่านั้น
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 {} \;
คุณพยายามค้นหาข้อความในไฟล์หรือไม่? คุณสามารถใช้ grep สำหรับสิ่งนั้นได้ ...
grep searchterm *
ในการแสดงรายการและดูเนื้อหาของไฟล์ 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 ^# {} \;
find -name '*.foo' -printทำงานได้ดีสำหรับฉัน ... ขอบคุณ