ทำไมการวนซ้ำจึงไม่ทำให้เกิดข้อผิดพลาด“ การโต้แย้งยาวเกินไป”


9

ฉันพบว่าสิ่งนี้จะทำให้เกิดข้อผิดพลาด "การโต้เถียงนานเกินไป":

ls *.*

และนี่จะไม่ยกมันขึ้นมา:

for file in *.*
do
    echo $file
done

ทำไม?


คุณใช้เปลือกเดียวกันในการทดสอบทั้งสองครั้งหรือไม่ อาจ/bin/bashเทียบกับ/bin/sh(ซึ่งอาจเป็นลิงก์ไปยังเส้นประ)
maxschlepzig

ใช่ฉันทำการทดลองกับไฟล์ 10,000 ไฟล์ด้วยชื่อไฟล์ซึ่งค่อนข้างยาว "ls *" ล้มเหลวและ "สำหรับ f ใน *" สำเร็จ
lamwaiman1988

คำตอบ:


13

ข้อผิดพลาด“ การโต้แย้งยาวเกินไป” E2BIGเกิดจากการexecveเรียกระบบหากขนาดรวมของการขัดแย้ง (รวมถึงสภาพแวดล้อมในบางระบบ) มีขนาดใหญ่เกินไป การexecveเรียกเป็นสิ่งที่เริ่มต้นกระบวนการภายนอกโดยเฉพาะอย่างยิ่งการโหลดไฟล์เรียกทำงานที่แตกต่างกัน (มีการเรียกที่แตกต่างกันforkสำหรับการเรียกใช้กระบวนการที่แยกต่างหากซึ่งรหัสยังคงมาจากไฟล์ปฏิบัติการเดียวกัน) ห่วงเป็นโครงสร้างเปลือกภายในดังนั้นจึงไม่เกี่ยวข้องกับการเรียกร้องfor execveคำสั่งls *.*ทำให้เกิดข้อผิดพลาดไม่ใช่เมื่อ glob ถูกขยาย แต่เมื่อlsถูกเรียก

execveล้มเหลวด้วยข้อผิดพลาดE2BIGเมื่อขนาดรวมของการขัดแย้งกับคำสั่งที่มีขนาดใหญ่กว่าขีด จำกัดARG_MAX คุณสามารถเห็นคุณค่าของขีด จำกัด getconf ARG_MAXนี้ในระบบของคุณด้วยคำสั่ง (เป็นไปได้ว่าคุณสามารถไปได้เกินขีด จำกัด นี้หากคุณมีหน่วยความจำเพียงพอให้อยู่ภายใต้ARG_MAXการรับประกันที่execveจะทำงานตราบเท่าที่ไม่มีข้อผิดพลาดที่ไม่เกี่ยวข้องเกิดขึ้น)


และทำไมเชลล์ถึงไม่มีขีด จำกัด ?
lamwaiman1988

1
@ gunbuster363 execveข้อ จำกัด ถูกบังคับใช้โดยเคอร์เนลทำให้มีข้อ จำกัด เนื่องจากอาร์กิวเมนต์ต้องถูกคัดลอกผ่านหน่วยความจำเคอร์เนล ณ จุดเดียวและกระบวนการของผู้ใช้ไม่สามารถอนุญาตให้ร้องขอจำนวนหน่วยความจำเชลล์โดยพลการ ภายในเชลล์นั้นไม่มีเหตุผลที่จะ จำกัด อะไรเลยสิ่งที่เหมาะกับหน่วยความจำเสมือนก็ใช้ได้
Gilles 'หยุดความชั่วร้าย'

5

ผมคิดว่าในตัวอย่างแรกlsจะดำเนินการจากbashผ่านfork/ สายระบบคู่ในหนึ่งวินาทีทั้งหมดทำงานอยู่ภายในexecbash

การexecโทรมีข้อ จำกัด การทำงานภายในของbashแทนไม่ได้ (หรือดีกว่ามีข้อ จำกัด ต่าง ๆ ที่ไม่มีส่วนเกี่ยวข้องกับexecจำนวนหน่วยความจำที่มีอยู่)


คุณสามารถค้นหาวงเงินที่จะexecในมักจะกำหนดให้เป็น/usr/include/linux/limits.h ARG_MAX
jw013

ถ้าเราใช้ shell for loop คุณคิดว่ารายการใหญ่ ๆ จะกินแรมทั้งหมดหรือไม่?
lamwaiman1988

คำตอบนี้ไม่ถูกต้อง ไม่ใช่ 'ภายใน' แต่เป็นเพียงข้อ จำกัด ของการขัดแย้งและคำสั่งที่แตกต่างกัน
พหุนาม

5

เพราะในกรณีที่lsมันเป็นข้อโต้แย้งและจำนวนข้อโต้แย้งมี จำกัด

ในกรณีของforรอบมันเป็นเพียงรายการ ไม่มีข้อ จำกัด (เท่าที่ฉันทราบ) สำหรับสิ่งนั้น


มีข้อ จำกัด แน่นอนสำหรับการขยายเชลล์ มันเกี่ยวข้องมากกับจำนวน RAM ที่คุณมีอยู่ .. ลองดูสิ ระบบ 4GB RAM ของฉันพัดปะเก็นที่ประมาณ 15.2 ล้าน 8 ไบต์:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O

4
@ เฟร็ดฉันไม่คิดว่าจะพูดถึงแรมว่าจำเป็นต้องมีขีด จำกัด
ŠimonTóth

2
อาจไม่จำเป็น แต่เป็นลักษณะของความคิดเห็น .. บางคนอาจพบว่ามันน่าสนใจหรือมีคุณค่า
Peter.O

@ เฟรด: จริง ๆ แล้วถ้าการขยายข้อโต้แย้งที่มีขนาดใหญ่มากเป็นปัญหาที่พบบ่อยมันเป็นไปได้ที่จะใช้มันโดยไม่ต้องเก็บทุกอย่างไว้ในความทรงจำ
Matteo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.