ก่อนอื่นให้ตัดคำตอบที่ไม่สำคัญ แต่ไม่เหมาะสม: ฉันสามารถใช้เคล็ดลับfind+ xargsหรือชุดรูปแบบ (เช่นเดียวfindกับ-exec) เพราะฉันต้องใช้การแสดงออกเช่นนี้ต่อการโทรเล็กน้อย ฉันจะกลับมาที่นี่ในตอนท้าย
ตอนนี้เป็นตัวอย่างที่ดีกว่าลองพิจารณา:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
ฉันจะส่งต่อสิ่งเหล่านี้เป็นอาร์กิวเมนต์ไปยังได้programอย่างไร
เพียงทำมันไม่ได้ทำเคล็ดลับ
$ ./program $(find -L some/dir -name \*.abc | sort)
ล้มเหลวเนื่องจากprogramได้รับอาร์กิวเมนต์ดังนี้
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
ดังที่เห็นได้เส้นทางที่มีช่องว่างถูกแยกออกและprogramพิจารณาว่าเป็นอาร์กิวเมนต์ที่ต่างกันสองรายการ
อ้างถึงมันใช้งานได้
ดูเหมือนว่าผู้ใช้มือใหม่เช่นตัวฉันเองเมื่อเผชิญกับปัญหาดังกล่าวมักจะเพิ่มคำพูดแบบสุ่มจนกว่าจะได้ผลในที่สุด - เฉพาะที่นี่ดูเหมือนจะไม่ช่วย ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
เนื่องจากเครื่องหมายคำพูดป้องกันการแยกคำไฟล์ทั้งหมดจึงถูกส่งเป็นอาร์กิวเมนต์เดียว
การอ้างอิงแต่ละเส้นทาง
แนวทางที่มีแนวโน้ม:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
คำพูดอยู่ที่นั่นแน่นอน แต่พวกเขาจะไม่ถูกตีความอีกต่อไป พวกเขาเป็นเพียงส่วนหนึ่งของสตริง ดังนั้นไม่เพียง แต่พวกเขาไม่ได้ป้องกันการแยกคำเท่านั้น แต่พวกเขายังมีข้อโต้แย้ง!
เปลี่ยน IFS
IFSแล้วฉันพยายามเล่นรอบกับ ฉันชอบfindที่มี-print0และsortที่มี-zอยู่แล้ว - เพื่อว่าพวกเขาจะมีปัญหาไม่มีใน "เส้นทางสาย" ตัวเอง เหตุใดจึงไม่บังคับให้แยกคำกับnullตัวละครและมีทั้งหมด
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
nullดังนั้นจึงยังคงแยกในพื้นที่และไม่ได้แยกบน
ฉันพยายามทำการIFSมอบหมายทั้งใน$(…)(ตามที่แสดงด้านบน) และก่อนหน้า./programนี้ นอกจากนี้ผมพยายามไวยากรณ์อื่น ๆ เช่น\0, \x0, \x00ทั้งยกมาด้วย'และเช่นเดียวกับที่มีและไม่มี" $ไม่มีสิ่งใดที่สร้างความแตกต่างได้ ...
และที่นี่ฉันไม่มีความคิด ฉันลองอีกสองสามอย่าง แต่ทุกอย่างดูเหมือนจะหมดไปกับปัญหาแบบเดียวกับที่ระบุไว้
ฉันจะทำอะไรได้อีก เป็นไปได้หรือไม่?
แน่นอนว่าฉันสามารถprogramยอมรับรูปแบบและทำการค้นหาตัวเอง แต่มันเป็นงานสองอย่างมากในขณะที่แก้ไขเป็นไวยากรณ์ที่เฉพาะเจาะจง (เช่นการให้ไฟล์โดยgrepตัวอย่างเช่น?)
นอกจากนี้ฉันสามารถทำให้programยอมรับไฟล์ที่มีรายการเส้นทาง จากนั้นฉันสามารถดัมพ์findนิพจน์ไปยังไฟล์ temp บางไฟล์และระบุพา ธ ไปยังไฟล์นั้นเท่านั้น สิ่งนี้สามารถรองรับได้ตามเส้นทางโดยตรงดังนั้นหากผู้ใช้มีเพียงเส้นทางง่ายๆก็สามารถให้ได้โดยไม่ต้องมีไฟล์ระดับกลาง แต่สิ่งนี้ดูไม่ดีนักเราจำเป็นต้องสร้างไฟล์เพิ่มเติมและดูแลไฟล์เหล่านั้นไม่ต้องพูดถึงการติดตั้งเพิ่มเติมที่จำเป็น (ในด้านบวกอย่างไรก็ตามมันอาจช่วยชีวิตสำหรับกรณีที่จำนวนไฟล์ที่เป็นอาร์กิวเมนต์เริ่มต้นที่จะทำให้เกิดปัญหากับความยาวบรรทัดคำสั่ง ... )
ในตอนท้ายให้ฉันเตือนคุณอีกครั้งว่าเทคนิคfind+ xargs(และเหมือนกัน) จะไม่ทำงานในกรณีของฉัน เพื่อความเรียบง่ายของคำอธิบายฉันแสดงเพียงอาร์กิวเมนต์เดียวเท่านั้น แต่กรณีจริงของฉันมีลักษณะเช่นนี้:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
ดังนั้นการxargsทำการค้นหาแบบหนึ่งยังทำให้ฉันมีวิธีการจัดการอีกวิธีหนึ่ง ...
mapfile(หรือคำพ้องความหมายreadarray) แต่มันใช้งานได้!