ฉันทำ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
โปรแกรมอ่านเข้ามาตรฐานของการแยกการป้อนข้อมูลที่พื้นที่สีขาว (ช่องว่างการขึ้นบรรทัดใหม่แท็บ ฯลฯ ) และผนวกจำนวนของคำสั่งและดำเนินการบรรทัดคำสั่ง จากนั้นดำเนินการอ่านอินพุตและเรียกใช้คำสั่งต่อไปจนกว่าจะหมดอินพุต รันคำสั่งได้บ่อยเท่าที่จำเป็นสำหรับอินพุตที่ได้รับ (จากในตัวอย่างนี้) xargs
xargs
grep something
xargs
xargs
grep
find
/dev/null
ลดข้อผิดพลาด
มีไม่กี่วิธีที่จะผ่านรายการของไฟล์ที่ส่งกลับโดยมีfind
คำสั่งไปยังcat
คำสั่ง cat
แต่ในทางเทคนิคไม่ได้ทั้งหมดท่อใช้และไม่มีท่อจริงโดยตรงกับ
วิธีที่ง่ายที่สุดคือใช้ backticks ( `
):
cat `find [whatever]`
นี้จะใช้เวลาการส่งออกของและมีประสิทธิภาพวางมันลงบนบรรทัดคำสั่งของfind
cat
วิธีนี้ใช้ไม่ได้ผลหากfind
มีเอาต์พุตมากเกินไป (มากกว่าที่จะใส่ในบรรทัดคำสั่ง) หรือถ้าเอาต์พุตมีอักขระพิเศษ (เช่นช่องว่าง)
ในเชลล์บางตัวรวมถึงbash
หนึ่งสามารถใช้$()
แทน backticks:
cat $(find [whatever])
นี่เป็นแบบพกพาน้อย แต่สามารถซ้อนได้ นอกเหนือจากนั้นมันก็มีข้อแม้เหมือนกันมากกับแบ็คคิก
เนื่องจากการเรียกใช้คำสั่งอื่น ๆ เกี่ยวกับสิ่งที่พบเป็นการใช้โดยทั่วไปfind
find จึงมีการ-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
ถึงการใช้\0
null (ตัวอักษร) คั่นระหว่างชื่อไฟล์และ-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
บรรทัดคำสั่ง วงเล็บจะถูกแทนที่ด้วยประปาชื่อไฟล์ลงในคำสั่งจากcat
find
มันใช้งานได้สำหรับฉัน
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
ทำงานได้ดีสำหรับฉัน ... ขอบคุณ