Dòng lệnh Bash và giới hạn đầu vào


90

Có một số loại giới hạn ký tự được áp đặt trong bash (hoặc các trình bao khác) trong thời gian đầu vào có thể là bao lâu? Nếu vậy, giới hạn ký tự đó là bao nhiêu?

Tức là Có thể viết một lệnh trong bash quá dài để dòng lệnh thực thi không? Nếu không có giới hạn bắt buộc, có giới hạn đề xuất không?


2
Các đầu vào hạn là rất khác so với lập luận hệ điều hành cấp hạn (lưu ý rằng một số thứ khác hơn đối số, chẳng hạn như biến môi trường, cũng được áp dụng đối với một trong đó). Lệnh đã tạo được chuyển tới hệ điều hành có thể có nhiều hoặc ít ký tự hơn lệnh shell đã tạo ra nó.
Charles Duffy

Câu trả lời:


125

Giới hạn độ dài của một dòng lệnh không phải do shell mà do hệ điều hành áp đặt. Giới hạn này thường nằm trong khoảng hàng trăm kilobyte. POSIX biểu thị giới hạn này ARG_MAXvà trên các hệ thống tuân theo POSIX, bạn có thể truy vấn nó bằng

$ getconf ARG_MAX    # Get argument limit in bytes

Ví dụ trên Cygwin, đây là 32000, và trên các hệ thống BSD và Linux khác nhau mà tôi sử dụng, nó nằm ở bất kỳ đâu từ 131072 đến 2621440.

Nếu bạn cần xử lý danh sách các tệp vượt quá giới hạn này, bạn có thể muốn xem xargstiện ích, tiện ích này gọi một chương trình lặp đi lặp lại với một tập hợp con các đối số không vượt quá ARG_MAX.

Để trả lời câu hỏi cụ thể của bạn, có, bạn có thể thử chạy một lệnh có danh sách đối số quá dài. Trình bao sẽ bị lỗi với một thông báo cùng với "danh sách đối số quá dài".

Lưu ý rằng đầu vào cho một chương trình (được đọc trên stdin hoặc bất kỳ trình mô tả tệp nào khác) không bị giới hạn (chỉ bởi các tài nguyên chương trình có sẵn). Vì vậy, nếu tập lệnh shell của bạn đọc một chuỗi thành một biến, bạn không bị giới hạn bởi ARG_MAX. Hạn chế này cũng không áp dụng cho nội trang vỏ.


Câu trả lời tốt, nhưng tôi muốn làm rõ. Nếu tôi có một cấu trúc cmd <<< "$LONG_VAR"và giá trị LONG_VAR vượt quá giới hạn, nó có làm hỏng lệnh của tôi không?
Krzysztof Jabłoński

1
@ KrzysztofJabłoński Không thể, vì nội dung của LONG_VARđược chuyển qua stdin - và điều đó được thực hiện hoàn toàn trong shell; nó không được mở rộng làm đối số cmd, vì vậy giới hạn ARG_MAX cho fork () / execute () không có tác dụng. Bạn có thể dễ dàng tự thử: tạo một biến có nội dung vượt quá ARG_MAX và chạy lệnh của bạn.
Jens

2
Đây là việc làm rõ, đối với các bản ghi: cho một file m4a 8 megabyte, tôi đã làm: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. Lưu ý không có lỗi.
Mike S

3
Cảnh báo nhỏ. Các biến môi trường cũng được tính. sysconf manpage > Rất khó sử dụng ARG_MAX vì nó không được chỉ định có bao nhiêu> không gian đối số cho thực thi (3) được sử dụng bởi các biến môi trường> của người dùng.
Gerrit

3
@ user188737 Tôi cảm thấy đó là một cảnh báo khá lớn trong BUGS . Ví dụ xargstrên hệ điều hành MacOS 10.12.6 giới hạn bao nhiêu nó sẽ cố gắng để đưa vào một exec()để ARG_MAX - 4096. Vì vậy, việc sử dụng script xargscó thể hoạt động, cho đến một ngày khi ai đó đặt quá nhiều thứ vào môi trường. Chạy vào điều này ngay bây giờ (làm việc xung quanh nó với xargs -s ???:).
neuralmer 20/02/18

44

Được rồi, hàng chục người. Vì vậy, tôi đã chấp nhận giới hạn độ dài dòng lệnh như phúc âm trong một thời gian khá dài. Vì vậy, phải làm gì với các giả định của một người? Đương nhiên- hãy kiểm tra chúng.

Tôi có một máy Fedora 22 theo ý của mình (nghĩa là: Linux với bash4). Tôi đã tạo một thư mục với 500.000 inodes (tệp) trong đó, mỗi inodes dài 18 ký tự. Độ dài dòng lệnh là 9.500.000 ký tự. Được tạo ra như vậy:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

Và chúng tôi lưu ý:

$ getconf ARG_MAX
2097152

Tuy nhiên, lưu ý rằng tôi có thể làm điều này:

$ echo * > /dev/null

Nhưng điều này không thành công:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

Tôi có thể chạy vòng lặp for:

$ for f in *; do :; done

là một nội trang shell khác.

Đọc kỹ tài liệu đểARG_MAX biết các trạng thái, Độ dài tối đa của đối số cho các hàm thực thi . Điều này có nghĩa là: Không cần gọi exec, không có ARG_MAXgiới hạn. Vì vậy, nó sẽ giải thích tại sao nội trang vỏ không bị hạn chế bởi ARG_MAX.

Và thực sự, tôi có thể lsthư mục của mình nếu danh sách đối số của tôi dài 109948 tệp hoặc khoảng 2.089.000 ký tự (cho hoặc nhận). Tuy nhiên, khi tôi thêm một tệp tên tệp 18 ký tự nữa, tôi nhận được lỗi Danh sách đối số quá dài . Vì vậy, ARG_MAXnó đang hoạt động như được quảng cáo: trình thực thi không thành công với nhiều hơn ARG_MAXký tự trong danh sách đối số - bao gồm, cần lưu ý, dữ liệu môi trường.


Hừ! Tôi đã không đọc câu trả lời hiện có để ngụ ý rằng nội trang phải chịu sự ràng buộc trong câu hỏi, nhưng chắc chắn có thể thấy cách ai đó có thể.
Charles Duffy

6
Vâng, tôi nghĩ rằng thật khó nhớ - đặc biệt là đối với afficianados dòng lệnh mới hơn - rằng tình huống gọi nội trang bash so với fork / thực thi một lệnh là khác nhau theo những cách không rõ ràng. Tôi muốn làm rõ điều đó. Một câu hỏi mà tôi luôn nhận được trong một cuộc phỏng vấn việc làm (với tư cách là một Linux Sysadmin) là, "Vì vậy, tôi có một loạt các tệp trong một thư mục. Làm thế nào để tôi lặp lại tất cả chúng ..." Người hỏi luôn lái xe về phía dòng giới hạn độ dài và muốn có giải pháp find / while hoặc xargs. Trong tương lai, tôi sẽ nói, "à quái- chỉ cần sử dụng vòng lặp for. Nó có thể xử lý được!" :-)
Mike S

@MikeS trong khi bạn có thể thực hiện vòng lặp for, nếu bạn có thể sử dụng combo find-xargs, bạn sẽ fork ít hơn rất nhiều và sẽ nhanh hơn. ;-)
Lester Cheung

4
@LesterCheung for f in *; do echo $f; donehoàn toàn không fork (tất cả các nội trang). Vì vậy, tôi không biết rằng một combo tìm-xargs sẽ nhanh hơn; nó chưa được thử nghiệm. Quả thực, tôi không biết vấn đề của OP là gì. Có lẽ find /path/to/directorysẽ không hữu ích với anh ta vì nó sẽ trả về tên đường dẫn của tệp. Có lẽ anh ấy thích sự đơn giản của một for f in *vòng lặp. Bất kể, cuộc trò chuyện là về giới hạn đầu vào dòng chứ không phải hiệu quả. Vì vậy, chúng ta hãy đi vào chủ đề, liên quan đến độ dài dòng lệnh.
Mike S

FWIW, vấn đề, như tôi nhớ lại, chỉ là cố gắng viết một trình bao trong C và xác định xem tôi nên cho phép đầu vào trong bao lâu.
Derek Halden

-3

Có giới hạn bộ đệm là 1024. Việc đọc sẽ chỉ treo giữa dán hoặc đầu vào. Để giải quyết vấn đề này, hãy sử dụng tùy chọn -e.

http://linuxcommand.org/lc3_man_pages/readh.html

-chúng tôi sử dụng Readline để lấy dòng trong một trình bao tương tác

Thay đổi đọc của bạn thành đọc -e và lỗi đầu vào dòng khó chịu sẽ biến mất.


1
Đây không phải là về read: "Tức là Có thể viết một lệnh trong bash quá dài để dòng lệnh thực thi không?"
Chai T. Rex

@ ChaiT.Rex bạn nói đúng, nhưng vấn đề ở đây là: hãy thử chạy Bash tương tác mà không có Readline, tức là bash --noediting, và tại dấu nhắc mới, hãy thử chạy lệnh echo somereallylongword, trong đó một số từ khóa dài hơn 4090 ký tự. Đã thử trên Ubuntu 18.04, từ này đã bị cắt bớt, vì vậy rõ ràng là nó có liên quan đến việc Readline không được bật.
Amir

@Amir Thật thú vị! Bạn nói đúng! Tôi đã cố gắng chỉnh sửa câu trả lời, nhưng sau đó tôi nhận ra rằng tùy chọn -e không áp dụng cho bash trong ngữ cảnh này (trong bash, nó thoát khỏi shell ngay lập tức khi bị lỗi). Và tôi không chắc tại sao Paul xoay người để đọc. Dù sao, có một giới hạn bộ đệm trong khoảng 4-5000 ký tự khi bash được bắt đầu bằng --noreadline. Đó là một tác dụng phụ mà tôi không biết hoặc không mong đợi.
Mike S
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.