ฉันจะรวมท่อได้อย่างไร ใน linux ของฉันค้นหาคำสั่ง -exec?


220

มันไม่ทำงาน สิ่งนี้สามารถทำได้ในการค้นหา? หรือฉันต้องการ xargs

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;

คำตอบ:


145

งานของการตีความสัญลักษณ์ไปป์เป็นคำสั่งเพื่อรันหลายกระบวนการและไพพ์เอาต์พุตของกระบวนการหนึ่งไปยังอินพุตของกระบวนการอื่นเป็นความรับผิดชอบของเชลล์ (/ bin / sh หรือเทียบเท่า)

ในตัวอย่างของคุณคุณสามารถเลือกที่จะใช้เปลือกระดับบนสุดของคุณเพื่อดำเนินการท่อดังนี้:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

ในแง่ของประสิทธิภาพผลลัพธ์นี้มีค่าใช้จ่ายในการเรียกใช้การค้นหาหนึ่งการเรียกใช้ zcat จำนวนมากและการเรียกใช้ agrep หนึ่งครั้ง

สิ่งนี้จะส่งผลให้เกิดกระบวนการ agrep เพียงอันเดียวซึ่งจะเกิดขึ้นซึ่งจะประมวลผลเอาต์พุตทั้งหมดที่เกิดจากการเรียกใช้ zcat จำนวนมาก

หากคุณมีเหตุผลบางอย่างที่ต้องการเรียกใช้ agrep หลายครั้งคุณสามารถทำได้:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

สิ่งนี้จะสร้างรายการคำสั่งโดยใช้ไพพ์เพื่อดำเนินการจากนั้นส่งคำสั่งเหล่านี้ไปยังเชลล์ใหม่เพื่อดำเนินการจริง (การละเว้น "| sh" เป็นวิธีที่ดีในการดีบักหรือดำเนินการบรรทัดคำสั่งแบบแห้ง)

ในแง่ของประสิทธิภาพผลลัพธ์นี้มีค่าใช้จ่ายการเรียกใช้การค้นหาหนึ่งการเรียกใช้ SH หนึ่งครั้งการเรียกใช้ zcat จำนวนมากและการเรียกใช้ agrep จำนวนมาก

โซลูชันที่มีประสิทธิภาพมากที่สุดในแง่ของจำนวนการเรียกใช้คำสั่งคือคำแนะนำจาก Paul Tomblin:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... ซึ่งมีค่าใช้จ่ายในการร้องขอการค้นหาหนึ่งการเรียกใช้ xargs หนึ่งการเรียกใช้ zcat สองสามครั้งและการเรียกใช้ agrep หนึ่งครั้ง


1
ข้อดีอีกอย่างของ xargs ก็คือคุณสามารถเพิ่มความเร็วด้วยซีพียูแบบมัลติคอร์ที่ทันสมัยยิ่งขึ้นโดยใช้สวิตช์ -P (-P 0)
flolo

ใช่ -P swich เป็นวิธีที่ดีในการเพิ่มความเร็วในการประมวลผลโดยทั่วไป น่าเสียดายที่คุณเสี่ยงต่อการส่งออกของกระบวนการ zcat แบบขนานที่ถูกไพพ์ไปยัง agrep interleaved ซึ่งจะส่งผลต่อผลลัพธ์ เอฟเฟกต์นี้สามารถแสดงได้โดยใช้: echo -e "1 \ n2" | xargs -P 0 -n 1 ใช่ | uniq
Rolf W. Rasmussen

@ อดัมฉันได้ทำการเปลี่ยนแปลงที่คุณแนะนำ
พอลทอมบลิน

ที่คุณสามารถติดตั้งคำสั่ง xjobs สวยงาม (จาก Solaris)
sehe

4
คำตอบที่ง่ายและมากขึ้นทั่วไปที่stackoverflow.com/a/21825690/42973-exec sh -c "… | … " \; :
Eric O Lebigot

279

การแก้ปัญหาเป็นเรื่องง่าย: ดำเนินการผ่าน sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;

17
สิ่งที่ OP พยายามทำสำเร็จนั้นสามารถพบกับคำแนะนำด้านบน แต่นี่คือคำตอบที่ถามคำถาม มีเหตุผลที่จะทำเช่นนี้ - exec มีประสิทธิภาพมากกว่าการใช้งานไฟล์ที่ส่งคืนโดย find โดยเฉพาะเมื่อรวมกับการทดสอบ ตัวอย่างเช่น: find geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ (ค้นหา $ DIR - maxdepth 1 | xargs grep -i spice | wc -l) -ge 5]] && echo $ DIR '\; จะส่งคืนไดเร็กทอรีทั้งหมดในพา ธ การค้นหาซึ่งมีผลรวมมากกว่า 5 บรรทัดระหว่างไฟล์ทั้งหมดในไดเร็กทอรีนั้นที่มีคำว่าเครื่องเทศ
swarfrat

3
คำตอบที่ดีที่สุด การ grepping ผลลัพธ์ทั้งหมด (ตามคำแนะนำอื่น ๆ ) ไม่เหมือนกับ grep แต่ละไฟล์ เคล็ดลับ: แทนที่จะเป็น sh คุณสามารถใช้เชลล์อื่น ๆ ที่คุณต้องการ (ฉันลองมันด้วยการทุบตีและมันก็ใช้ได้)
pagliuca

1
ตรวจสอบให้แน่ใจว่าไม่ได้มองข้าม-cตัวเลือก มิฉะนั้นคุณจะได้รับNo such file or directoryข้อความแสดงข้อผิดพลาดที่ทำให้งง
asmaier

นี่คือการแทนที่ ps ที่ยอดเยี่ยมซึ่งใช้ประโยชน์จากการค้นหาด้วยการวางท่อในเปลือก exec'd: / usr / bin / find / proc -mindepth 1 -maxdepth 1 -type d -regex '. * / [0-9] +' - พิมพ์ -exec bash -c "cat {} / cmdline | tr '\\ 0' ''; echo" \;
parity3

1
ตัวอย่างเช่นในการหาไฟล์และเปลี่ยนชื่อพวกเขาด้วยSEDใช้นิพจน์ปกติ find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei

16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

หวังว่าจะหลีกเลี่ยง - พิมพ์และ xargs ด้วยเหตุผลด้านประสิทธิภาพ บางทีนั่นอาจเป็นปัญหาของฉัน: ค้นหาไม่สามารถจัดการคำสั่ง
piped

สิ่งนี้ใช้ไม่ได้กับไฟล์ที่มีช่องว่างในชื่อ เพื่อแก้ไขแทนที่ - พิมพ์ด้วย -print0 และเพิ่มตัวเลือก -0 ใน xargs
Adam Rosenfield

2
@someguy - Wha? หลีกเลี่ยงการใช้ xargs ด้วยเหตุผลด้านประสิทธิภาพหรือไม่ โทรหนึ่งตัวอย่างของ zcat และผ่านมันรายการหลายไฟล์เป็นไกลมีประสิทธิภาพมากขึ้นกว่า exec ไอเอ็นจีตัวอย่างใหม่ของมันสำหรับไฟล์พบกัน
Sherm Pendley

@Adam - ฉันได้ทำการเปลี่ยนแปลงที่คุณแนะนำ 99% ของเวลาที่ฉันพบมันอยู่ในไดเรกทอรีซอร์สโค้ดของฉันและไม่มีไฟล์ใดที่มีช่องว่างดังนั้นฉันจึงไม่ต้องกังวลกับ print0 ตอนนี้ไดเรกทอรีเอกสารของฉันในทางกลับกันฉันจำ print0 ได้
พอลทอมบลิน

10

คุณยังสามารถไพพ์ไปยังwhileลูปที่สามารถดำเนินการหลายอย่างกับไฟล์ที่findตั้งอยู่ ดังนั้นนี่คือสิ่งที่มองหาที่jarเก็บถาวรสำหรับไฟล์คลาส java ที่กำหนดในโฟลเดอร์ที่มี distro jarไฟล์ขนาดใหญ่

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

จุดสำคัญคือการwhileวนรอบมีหลายคำสั่งอ้างอิงชื่อไฟล์ที่ส่งผ่านคั่นด้วยเซมิโคลอนและคำสั่งเหล่านี้สามารถรวมไปป์ ดังนั้นในตัวอย่างนั้นฉันสะท้อนชื่อของไฟล์ที่ตรงกันจากนั้นแสดงรายการสิ่งที่อยู่ในการกรองไฟล์เก็บถาวรสำหรับชื่อคลาสที่ระบุ ผลลัพธ์ดูเหมือนว่า:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / ติดตามได้ / list / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / ปลั๊กอิน / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

ในเปลือกทุบตีของฉัน (xubuntu10.04 / xfce) มันจะทำให้ classname ที่จับคู่เป็นตัวหนาเป็นfgrepไฮไลต์สตริงที่ตรงกัน; ทำให้ง่ายต่อการค้นหารายการjarไฟล์หลายร้อยไฟล์ที่ถูกค้นหาและดูรายการที่ตรงกันได้อย่างง่ายดาย

บน windows คุณสามารถทำสิ่งเดียวกันกับ:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

โปรดทราบว่าในหน้าต่างตัวคั่นคำสั่งคือ '&' ไม่ '; และ '@' จะระงับเสียงสะท้อนของคำสั่งเพื่อให้เอาต์พุตที่เป็นระเบียบเหมือนกับ linux ค้นหาเอาต์พุตด้านบน แม้ว่าfindstrจะไม่ทำให้สตริงที่ตรงกันเป็นตัวหนาดังนั้นคุณต้องมองเข้าไปที่เอาต์พุตให้ใกล้ขึ้นเพื่อดูชื่อคลาสที่ตรงกัน ปรากฎว่าคำสั่ง windows 'for' รู้ถึงเทคนิคบางอย่างเช่นการวนลูปผ่านไฟล์ข้อความ ...

สนุก


2

ฉันพบว่าการรันคำสั่ง string shell (sh -c) ทำงานได้ดีที่สุดตัวอย่างเช่น:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;

0

หากคุณกำลังมองหาทางเลือกง่ายๆสิ่งนี้สามารถทำได้โดยใช้การวนซ้ำ:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

หรือแบบฟอร์มทั่วไปที่เข้าใจง่ายขึ้น:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

และแทนที่ {} โดย $ i ใน YOUR_EXEC_COMMAND_AND_PIPES

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