Tại sao vòng lặp không nâng cao đối số lỗi quá dài lỗi lỗi?


9

Tôi thấy rằng điều này sẽ gây ra lỗi "đối số quá dài":

ls *.*

Và điều này sẽ không nâng cao nó:

for file in *.*
do
    echo $file
done

Tại sao?


Bạn đã sử dụng cùng một vỏ trong cả hai thí nghiệm? Có lẽ /bin/bashso với /bin/sh(mà có lẽ là một liên kết đến dash)?
maxschlepzig

Có, tôi đã thực hiện thử nghiệm với 10000 tệp có tên tệp khá dài. "ls *" không thành công và "cho f trong *" đã thành công.
lamwaiman1988

Câu trả lời:


13

Đối số trên mạng quá dài Lỗi lỗi được E2BIGđưa ra bởi lệnh execvegọi hệ thống nếu tổng kích thước của các đối số (cộng với môi trường, trên một số hệ thống) quá lớn. Cuộc execvegọi này là cuộc gọi bắt đầu các quy trình bên ngoài, cụ thể tải một tệp thực thi khác (có một cuộc gọi khác fork, để chạy một quy trình riêng có mã vẫn từ cùng một tệp thực thi). Các forvòng lặp là một cấu trúc vỏ nội bộ, vì vậy nó không liên quan đến gọi execve. Lệnh ls *.*tăng lỗi không phải khi toàn cầu được mở rộng mà lslà khi được gọi.

execvekhông thành công với lỗi E2BIGkhi tổng kích thước của các đối số cho lệnh lớn hơn ARG_MAX giới hạn . Bạn có thể thấy giá trị của giới hạn này trên hệ thống của bạn bằng lệnh getconf ARG_MAX. (Có thể là bạn có thể vượt quá giới hạn này nếu bạn có đủ bộ nhớ; giữ dưới sự ARG_MAXđảm bảo execvesẽ hoạt động miễn là không xảy ra lỗi không liên quan.)


và tại sao vỏ không có giới hạn?
lamwaiman1988

1
@ gunbuster363 execveGiới hạn được thực thi bởi kernel, nó đặt giới hạn vì các đối số cần được sao chép qua bộ nhớ kernel tại một điểm và các quy trình người dùng không thể được phép yêu cầu số lượng bộ nhớ shell tùy ý. Bên trong lớp vỏ, không có lý do gì để có bất kỳ giới hạn nào, bất cứ điều gì phù hợp với bộ nhớ ảo đều ổn.
Gilles 'SO- ngừng trở nên xấu xa'

5

Tôi giả sử rằng trong ví dụ đầu tiên lsđược thực hiện bashthông qua một cuộc gọi hệ thống fork/ execcặp, trong ví dụ thứ hai, tất cả các công việc là nội bộ bash.

Cuộc execgọi có giới hạn, bashthay vào đó , công việc nội bộ không có (hoặc tốt hơn, có các giới hạn khác nhau không liên quan gì exec, có lẽ là dung lượng bộ nhớ khả dụng).


Bạn có thể tìm thấy những giới hạn exectrong /usr/include/linux/limits.hthường, định nghĩa là ARG_MAX.
jw013

Nếu chúng tôi sử dụng shell cho vòng lặp, bạn có nghĩ rằng một danh sách lớn các mặt hàng sẽ tiêu thụ hết RAM không?
lamwaiman1988

Câu trả lời này không chính xác. Nó không phải là 'nội bộ', chỉ là giới hạn cho các đối số và lệnh là khác nhau.
đa thức

5

Bởi vì trong trường hợp của lsnó là một đối số và số lượng đối số bị hạn chế.

Trong trường hợp của forchu kỳ, nó chỉ là một danh sách các mục. Không có giới hạn (theo như tôi biết) cho điều đó.


Chắc chắn có một giới hạn cho việc mở rộng vỏ. Nó liên quan rất nhiều đến lượng RAM bạn có sẵn .. Hãy thử điều này; hệ thống RAM 4GB của tôi thổi một miếng đệm vào khoảng 15,2 triệu đối số 8 byte:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O

4
@fred Tôi thực sự không nghĩ rằng việc đề cập đến RAM là giới hạn là cần thiết.
Šimon Tóth

2
Nó có thể không cần thiết, nhưng đó là bản chất của ý kiến ​​.. ai đó có thể thấy nó thú vị, hoặc thậm chí có giá trị.
Peter.O

@fred: thực sự là có, nếu việc mở rộng các đối số rất lớn là một vấn đề phổ biến, có thể thực hiện nó mà không giữ mọi thứ trong bộ nhớ.
Matteo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.