ด้วยเครื่องมือ GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
คุณสามารถทำมาตรฐาน:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
แต่นั่นจะรันสอง greps ต่อไฟล์ หากต้องการหลีกเลี่ยงการเรียกใช้ไฟล์จำนวนมากgrep
และยังพกพาได้ในขณะที่ยังอนุญาตให้ใช้อักขระใด ๆ ในชื่อไฟล์คุณสามารถทำได้:
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
แนวคิดที่จะแปลงผลลัพธ์ของfind
รูปแบบที่เหมาะสมสำหรับ xargs (ที่คาดว่าจะว่างเปล่า (SPC / TAB / NL และช่องว่างอื่น ๆ จากสถานที่ของคุณด้วยการใช้งานบางส่วนของxargs
) รายการแยกของคำที่เดียวคำพูดสองครั้งและเครื่องหมายแบ็กสแลช ช่องว่างหลบหนีและกันและกัน)
โดยทั่วไปแล้วคุณไม่สามารถประมวลผลเอาต์พุตได้find -print
เนื่องจากจะแยกชื่อไฟล์ด้วยอักขระขึ้นบรรทัดใหม่และไม่หนีอักขระขึ้นบรรทัดใหม่ที่พบในชื่อไฟล์ เช่นถ้าเราเห็น:
./a
./b
เรามีวิธีที่จะรู้ว่าไม่ว่าจะเป็นไฟล์เดียวเรียกว่าไม่มีb
ในไดเรกทอรีที่เรียกว่าa<NL>.
หรือถ้ามันเป็นสองไฟล์และa
b
โดยใช้.//.
เนื่องจาก//
ไม่สามารถปรากฏเป็นอย่างอื่นในเส้นทางของไฟล์เป็นผลลัพธ์โดยfind
(เนื่องจากไม่มีสิ่งใดเป็นไดเรกทอรีที่มีชื่อว่างและ/
ไม่ได้รับอนุญาตในชื่อไฟล์) เรารู้ว่าถ้าเราเห็นบรรทัดที่มีอยู่//
นั่นคือ บรรทัดแรกของชื่อไฟล์ใหม่ ดังนั้นเราสามารถใช้awk
คำสั่งนั้นเพื่อหลีกเลี่ยงอักขระขึ้นบรรทัดใหม่ทั้งหมด แต่อักขระที่อยู่ข้างหน้าบรรทัดเหล่านั้น
หากเรานำตัวอย่างข้างต้นfind
จะแสดงผลในกรณีแรก (หนึ่งไฟล์):
.//a
./b
awk ใดที่หนีไป:
.//a\
./b
เพื่อให้xargs
เห็นว่ามันเป็นข้อโต้แย้งอย่างหนึ่ง และในกรณีที่สอง (สองไฟล์):
.//a
.//b
ซึ่งawk
จะปล่อยให้เป็นไปตามดังนั้นxargs
เห็นสองข้อโต้แย้ง