คำสั่งนั้นขึ้นอยู่กับเชลล์ที่สร้างอาร์กิวเมนต์จำนวน 5,000 ข้อและส่งต่อไปยังprintfสิ่งที่ไม่สนใจ ในขณะที่มันอาจดูค่อนข้างเร็ว - และสัมพันธ์กับบางสิ่ง - เชลล์จะต้องสร้างสตริงเหล่านั้นทั้งหมดเป็น args (และกำหนดขอบเขต)และอื่น ๆ
นอกเหนือจากข้อเท็จจริงที่ว่า Hs ที่สร้างขึ้นไม่สามารถพิมพ์ได้จนกว่าเชลล์จะทำซ้ำถึง 5,000 ครั้งแรกคำสั่งนั้นจะมีค่าใช้จ่ายในหน่วยความจำทั้งหมดที่ใช้ในการจัดเก็บและกำหนดขอบเขตอาร์กิวเมนต์สตริงตัวเลขให้เป็นprintf บวกกับ Hs เช่นเดียวกับที่คุณสามารถทำได้:
printf %05000s|tr \ H
... ซึ่งสร้างสตริงของช่องว่าง 5000 - ซึ่งอย่างน้อยที่สุดจะมีเพียงไบต์เดียวต่อหนึ่งและไม่มีค่าใช้จ่ายใด ๆ ในการกำหนดเขตเนื่องจากไม่มีการคั่น การทดสอบบางอย่างบ่งชี้ว่าแม้กระทั่งน้อยถึง 5,000 ไบต์ค่าใช้จ่ายของทางแยกและท่อที่จำเป็นสำหรับการtrมีค่ามันแม้ในกรณีนี้และมันเกือบจะทุกครั้งคือเมื่อตัวเลขสูงขึ้น
ฉันวิ่ง ...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...และ...
time bash -c 'printf %05000s|tr \ H' >/dev/null
แต่ละชิ้นมีความยาวประมาณ 5 เท่า(ไม่มีข้อมูลเชิงวิทยาศาสตร์ที่นี่ - เพียงอย่างเดียวเท่านั้น)และรุ่นส่วนขยายรั้งเฉลี่ยน้อยกว่า 0.02 วินาทีในเวลาประมวลผลทั้งหมด แต่trรุ่นมาโดยเฉลี่ยประมาณ 0.12 วินาที - และtrรุ่นเอาชนะได้ ทุกเวลา. ฉันไม่สามารถบอกได้ว่าฉันประหลาดใจ - {brace expansion}เป็นคุณสมบัติชวเลขเชลล์แบบโต้ตอบที่มีประโยชน์ แต่มักจะเป็นสิ่งที่ค่อนข้างสิ้นเปลืองในการทำสิ่งที่เกี่ยวข้องกับการเขียนสคริปต์ รูปแบบทั่วไป:
for i in {[num]..[num]}; do ...
... เมื่อคุณคิดเกี่ยวกับมันเป็นสอง forลูป - อย่างแรกคือภายในและส่อให้เห็นว่าเชลล์ต้องวนในบางวิธีเพื่อสร้างตัววนซ้ำก่อนที่จะบันทึกพวกมันทั้งหมดและวนซ้ำอีกครั้งสำหรับforลูปของคุณ สิ่งเหล่านี้มักจะทำได้ดีกว่าเช่น:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... เนื่องจากคุณเก็บค่าเพียงไม่กี่ค่าและเขียนทับค่าเหล่านั้นในขณะที่คุณทำเช่นเดียวกับการทำซ้ำในขณะที่คุณสร้างค่า iterables
อย่างไรก็ตามเช่นเดียวกับการเว้นวรรคที่กล่าวถึงก่อนหน้านี้คุณยังสามารถใช้printfzeropad เป็นจำนวนหลักได้ตามต้องการเช่น:
printf %05000d
ฉันทำทั้งสองอย่างโดยไม่มีข้อโต้แย้งเพราะสำหรับทุกอาร์กิวเมนต์ที่ระบุในprintfสตริงรูปแบบของเมื่อข้อโต้แย้งไม่พบสตริงที่เป็นโมฆะถูกใช้ - ซึ่งถูกตีความว่าเป็นศูนย์สำหรับอาร์กิวเมนต์หลักหรือสตริงที่ว่างเปล่าสำหรับสตริง
นี่คือด้านอื่น ๆ(และ - ในความคิดของฉัน -ด้านประสิทธิภาพของเหรียญ) เมื่อเปรียบเทียบกับคำสั่งในคำถาม - ในขณะที่เป็นไปได้ที่จะไม่ได้อะไรจากสิ่งที่คุณทำเมื่อคุณprintf %.0จำกัดความยาวของอาร์กิวเมนต์แต่ละข้อ เป็นไปได้ที่จะได้อะไรจากอะไร
ยังเร็วกว่าสำหรับจำนวนไบต์ที่สร้างขึ้นที่คุณสามารถใช้ddเช่น:
printf \\0| dd bs=64k conv=sync
... และ w / ไฟล์ปกติdd's seek=[num]อาร์กิวเมนต์สามารถนำมาใช้ให้เป็นประโยชน์มากขึ้น คุณสามารถรับบรรทัดใหม่ 64k แทนที่จะเป็นโมฆะถ้าคุณเพิ่ม,unblock cbs=1ไปด้านบนและจากนั้นสามารถฉีดสตริงตามอำเภอใจต่อบรรทัดด้วยpasteและ/dev/null- แต่ในกรณีนั้นถ้ามันพร้อมให้คุณคุณอาจใช้:
yes 'output string forever'
นี่คือddตัวอย่างเพิ่มเติม:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... ซึ่งสร้าง(หรือตัดทอน)\0NULไฟล์เต็มในไดเรกทอรีปัจจุบันชื่อ H.txt ขนาด 5000 ไบต์ ddค้นหาตรงไปยัง offset และ NUL เติมให้เต็ม
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... ซึ่งสร้างไฟล์ที่มีชื่อและขนาดเดียวกัน แต่เติมตัวอักษร w / H จะใช้ประโยชน์จากddพฤติกรรม spec'd ของการเขียนออกมาอย่างน้อยหนึ่ง null บล็อกเต็มรูปแบบในกรณีของข้อผิดพลาดการอ่านเมื่อnoerrorและsyncแปลงที่ระบุไว้(และ - ไม่count=- มีแนวโน้มที่จะไปนานกว่าที่คุณอาจต้องการ)และจงใจเปลี่ยนเส้นทาง ไฟล์อธิบายอย่างเป็นลายลักษณ์อักษรที่ddstdin ของ
tcshหรือzsh,repeat 5000 printf Hง่ายต่อการเข้าใจ ด้วยperl:print "H" x 5000(โปรดทราบว่านั่น{1..5000}คือตัวดำเนินการ zsh ที่ได้รับแรงบันดาลใจจากperl's1..5000และคัดลอกมาโดย ksh93 และ bash)