ก่อนอื่นให้ตัดคำตอบที่ไม่สำคัญ แต่ไม่เหมาะสม: ฉันสามารถใช้เคล็ดลับ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
) แต่มันใช้งานได้!