ไม่มีวิธีใดในการป้องกันช่องว่างในการขยาย backtick (หรือ $ (... )) ใช่ไหม
ไม่ไม่มี ทำไมถึงเป็นอย่างนั้น?
Bash ไม่มีทางรู้ว่าควรจะป้องกันอะไรและอะไรไม่ควร
ไม่มีอาร์เรย์ในไฟล์ / ไพพ์ยูนิกซ์ มันเป็นแค่กระแสไบต์ คำสั่งภายใน``
หรือ$()
ส่งออกกระแสซึ่งทุบตีกลืนและถือว่าเป็นสายเดียว เมื่อถึงจุดนี้คุณมีสองทางเลือกเท่านั้น: ใส่ไว้ในเครื่องหมายอัญประกาศเพื่อให้เป็นสตริงเดียวหรือวางไว้เปล่า ๆ เพื่อให้ทุบตีมันแยกตามพฤติกรรมที่กำหนดไว้
ดังนั้นสิ่งที่คุณต้องทำถ้าคุณต้องการอาเรย์คือการกำหนดรูปแบบไบต์ที่มีอาเรย์และนั่นคือสิ่งที่เครื่องมือชอบxargs
และfind
ทำ: ถ้าคุณเรียกใช้พวกเขาด้วย-0
โต้แย้งพวกเขาทำงานตามรูปแบบอาเรย์ไบนารีที่สิ้นสุดองค์ประกอบ null null เพิ่ม semantics ให้กับ stream ไบต์ทึบแสง
น่าเสียดายที่bash
ไม่สามารถกำหนดค่าให้แยกสตริงบนไบต์ที่ว่างได้ ขอบคุณ/unix//a/110108/17980สำหรับแสดงให้เราเห็นว่าzsh
สามารถทำได้
xargs
คุณต้องการให้คำสั่งรันครั้งเดียวและคุณบอกว่าวิธีxargs -0 -n 10000
แก้ปัญหาของคุณ ไม่รับประกันว่าหากคุณมีพารามิเตอร์มากกว่า 10,000 พารามิเตอร์คำสั่งของคุณจะทำงานมากกว่าหนึ่งครั้ง
ถ้าคุณต้องการทำให้มันรันอย่างเคร่งครัดหนึ่งครั้งหรือล้มเหลวคุณต้องระบุ-x
อาร์กิวเมนต์และ-n
อาร์กิวเมนต์ที่มีขนาดใหญ่กว่า-s
อาร์กิวเมนต์ (จริง ๆ : ใหญ่พอที่ทั้งกลุ่มของอาร์กิวเมนต์ที่มีความยาวเป็นศูนย์รวมกับชื่อของคำสั่งจะไม่พอดี-s
ขนาด) ( man xargsดูข้อความที่ตัดตอนมาด้านล่าง)
ระบบที่ฉันใช้อยู่ในปัจจุบันมีสแต็ก จำกัด ประมาณ 8M ดังนั้นนี่คือขีด จำกัด ของฉัน:
$ printf '%s\0' -- {1..1302582} | xargs -x0n 2076858 -s 2076858 /bin/true
xargs: argument list too long
$ printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true
(no output)
ทุบตี
หากคุณไม่ต้องการมีส่วนร่วมกับคำสั่งภายนอกวงวนการอ่านขณะป้อนอาร์เรย์ดังที่แสดงไว้ใน/unix//a/110108/17980เป็นวิธีเดียวในการทุบตีเพื่อแบ่งสิ่ง ไบต์ว่าง
แนวคิดในการจัดหาสคริปต์( . ... "$@" )
เพื่อหลีกเลี่ยงข้อ จำกัด ขนาดสแต็กต์นั้นยอดเยี่ยม (ฉันลองใช้งานได้!) แต่อาจไม่สำคัญสำหรับสถานการณ์ปกติ
การใช้ fd พิเศษสำหรับไปป์กระบวนการนั้นมีความสำคัญหากคุณต้องการอ่านอย่างอื่นจาก stdin แต่ไม่เช่นนั้นคุณจะไม่ต้องการมัน
ดังนั้นวิธี "ดั้งเดิม" ที่ง่ายที่สุดสำหรับความต้องการของใช้ในครัวเรือนประจำวัน:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
ถ้าคุณชอบทรีโปรเซสของคุณที่สะอาดและน่าดูเมธอดนี้อนุญาตให้คุณทำexec mynonscript "${files[@]}"
ซึ่งจะลบกระบวนการ bash ออกจากหน่วยความจำแทนที่ด้วยคำสั่งที่เรียกว่า xargs
จะยังคงอยู่ในหน่วยความจำเสมอในขณะที่คำสั่งที่เรียกใช้ทำงานแม้ว่าคำสั่งนั้นจะทำงานเพียงครั้งเดียว
สิ่งที่พูดกับวิธีทุบตีพื้นเมืองคือ:
$ time { printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true; }
real 0m2.014s
user 0m2.008s
sys 0m0.172s
$ time {
args=()
while IFS= read -rd '' arg; do
args+=( "$arg" )
done < <(printf '%s\0' -- $(echo {1..1302581}))
/bin/true "${args[@]}"
}
bash: /bin/true: Argument list too long
real 107m51.876s
user 107m38.532s
sys 0m7.940s
bash ไม่เหมาะสำหรับการจัดการอาเรย์
ผู้ชาย xargs :
-n max-args
ใช้อาร์กิวเมนต์ max-args มากที่สุดต่อบรรทัดคำสั่ง อาร์กิวเมนต์น้อยกว่า max-args จะถูกใช้หากเกินขนาด (ดูตัวเลือก -s) ยกเว้นว่ามีการกำหนดตัวเลือก -x ซึ่ง xargs จะออกจากกรณีนี้
-s max-chars
ใช้อักขระสูงสุด max-chars ต่อบรรทัดคำสั่งรวมถึงคำสั่งและอาร์กิวเมนต์เริ่มต้นและการยกเลิก nulls ที่ส่วนท้ายของสตริงอาร์กิวเมนต์ ค่าสูงสุดที่อนุญาตนั้นขึ้นอยู่กับระบบและคำนวณเป็นข้อจำกัดความยาวอาร์กิวเมนต์สำหรับ exec น้อยกว่าขนาดของสภาพแวดล้อมของคุณน้อยกว่า 2048 ไบต์ของ headroom หากค่านี้มากกว่า 128KiB จะใช้ 128Kib เป็นค่าเริ่มต้น มิฉะนั้นค่าเริ่มต้นคือสูงสุด 1KiB คือ 1024 ไบต์
-x
ออกหากขนาด (ดูตัวเลือก -s) เกิน
IFS="
ขึ้นบรรทัดใหม่"
) แต่จำเป็นต้องเรียกใช้สคริปต์เหนือชื่อไฟล์ทั้งหมดหรือไม่ หากไม่ใช่ให้ลองใช้ค้นหาตัวเองเพื่อรันสคริปต์สำหรับแต่ละไฟล์