Danh sách đối số của tôi quá dài. Làm thế nào để tôi đối phó với nó, mà không thay đổi lệnh của tôi?


18

Khi tôi chạy một lệnh như thế ls */*/*/*/*.jpg, tôi gặp lỗi

-bash: /bin/ls: Argument list too long

Tôi biết lý do tại sao điều này xảy ra: đó là bởi vì có giới hạn hạt nhân trên lượng không gian cho các đối số cho một lệnh. Lời khuyên tiêu chuẩn là thay đổi lệnh tôi sử dụng, để tránh yêu cầu quá nhiều không gian cho các đối số (ví dụ: sử dụng findxargs).

Nếu tôi không muốn thay đổi lệnh thì sao? Nếu tôi muốn tiếp tục sử dụng cùng một lệnh thì sao? Làm thế nào tôi có thể làm cho mọi thứ "chỉ hoạt động", mà không gặp lỗi này? Những giải pháp có sẵn?


Đọc hữu ích: Bash FAQ 95 . Không thay đổi lệnh của bạn, bạn không thể làm gì nhiều ngoài việc biên dịch lại để tăng kích thước tối đa của danh sách đối số hoặc thay đổi cấu trúc thư mục của bạn để có ít tệp hơn.
jw013

1
@ jw013 dựa trên phiên bản kernel linux, có thể tăng danh sách đối số - xem unix.stackexchange.com/a/45161/8979 để biết chi tiết về sự thay đổi trong các hệ thống gần đây.
Ulrich Dangel

@UlrichDangel, Yup, hoàn toàn có thể! Xem câu trả lời của tôi; câu trả lời của tôi cho thấy cách thực hiện (trên Linux, với một hạt nhân đủ gần đây).
DW

Câu trả lời:


26

Trên Linux, lượng không gian tối đa cho các đối số lệnh là 1/4 của dung lượng ngăn xếp có sẵn. Vì vậy, một giải pháp là tăng lượng không gian có sẵn cho ngăn xếp.

Phiên bản ngắn: chạy một cái gì đó như

ulimit -s 65536

Phiên bản dài hơn: Lượng không gian mặc định có sẵn cho ngăn xếp là khoảng 8192 KB. Bạn có thể thấy lượng không gian có sẵn, như sau:

$ ulimit -s
8192

Chọn một số lượng lớn hơn và đặt lượng không gian có sẵn cho ngăn xếp. Ví dụ: nếu bạn muốn thử cho phép tối đa 65536 KB cho ngăn xếp, hãy chạy nó:

$ ulimit -s 65536

Bạn có thể cần phải chơi xung quanh với mức độ lớn của nhu cầu này, sử dụng thử và sai. Trong nhiều trường hợp, đây là một giải pháp nhanh chóng-và-bẩn đó sẽ loại bỏ sự cần thiết phải sửa đổi lệnh và làm việc ra cú pháp của find, xargsvv (mặc dù tôi nhận ra có những lợi ích khác để làm như vậy).

Tôi tin rằng đây là đặc thù của Linux. Tôi nghi ngờ nó có thể sẽ không giúp ích cho bất kỳ hệ điều hành Unix nào khác (chưa được thử nghiệm).


1
Bạn có thể xác minh như thế này rằng nó đã hoạt động: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex

2

Đây bài viết Linux Journal cho 4 giải pháp. Chỉ có giải pháp thứ tư không liên quan đến việc thay đổi lệnh:

Phương pháp # 4 liên quan đến việc tăng thủ công số lượng trang được phân bổ trong kernel cho các đối số dòng lệnh. Nếu bạn nhìn vào tệp bao gồm / linux / binfmts.h, bạn sẽ tìm thấy phần sau gần đầu:

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

Để tăng dung lượng bộ nhớ dành riêng cho các đối số dòng lệnh, bạn chỉ cần cung cấp giá trị MAX_ARG_PAGES với số cao hơn. Khi chỉnh sửa này được lưu, chỉ cần biên dịch lại, cài đặt và khởi động lại vào kernel mới như bạn vẫn làm bình thường.

Trên hệ thống kiểm tra của riêng tôi, tôi đã cố gắng giải quyết tất cả các vấn đề của mình bằng cách nâng giá trị này lên 64. Sau khi thử nghiệm rộng rãi, tôi đã không gặp phải một vấn đề nào kể từ khi chuyển đổi. Điều này hoàn toàn được mong đợi vì ngay cả khi MAX_ARG_PAGESđược đặt thành 64, dòng lệnh dài nhất có thể tôi có thể tạo ra sẽ chỉ chiếm 256KB bộ nhớ hệ thống - không nhiều bằng các tiêu chuẩn phần cứng hệ thống ngày nay.

Ưu điểm của Phương pháp số 4 là rõ ràng. Bây giờ bạn có thể chỉ cần chạy lệnh như bình thường và hoàn thành thành công. Những nhược điểm cũng rõ ràng không kém. Nếu bạn tăng dung lượng bộ nhớ khả dụng cho dòng lệnh vượt quá dung lượng bộ nhớ hệ thống khả dụng, bạn có thể tạo một cuộc tấn công DOS trên hệ thống của riêng bạn và khiến nó bị sập. Trên các hệ thống nhiều người dùng nói riêng, ngay cả một mức tăng nhỏ cũng có thể có tác động đáng kể vì mỗi người dùng sau đó được cấp phát bộ nhớ bổ sung. Do đó, luôn luôn kiểm tra rộng rãi trong môi trường của chính bạn, vì đây là cách an toàn nhất để xác định xem Phương pháp số 4 có phải là một lựa chọn khả thi cho bạn hay không.

Tôi đồng ý rằng giới hạn là gây phiền nhiễu nghiêm trọng.


1

Thay vì ls */*/*/*/*.jpg, hãy thử:

echo */*/*/*/*.jpg | xargs ls

xargs(1) biết, số lượng đối số tối đa trên hệ thống là bao nhiêu và sẽ phá vỡ đầu vào tiêu chuẩn của nó để gọi dòng lệnh được chỉ định nhiều lần mà không có nhiều đối số hơn giới hạn đó, bất kể là gì (bạn cũng có thể đặt nó thấp hơn tối đa của hệ điều hành bằng cách sử dụng -ntùy chọn).

Ví dụ: giả sử, giới hạn là 3 đối số và bạn có năm tệp. Trong trường hợp đó xargssẽ thực thi lshai lần:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Thường thì điều này là hoàn toàn phù hợp, nhưng không phải lúc nào cũng vậy - ví dụ, bạn không thể dựa vào ls(1) sắp xếp tất cả các mục cho bạn một cách chính xác, bởi vì mỗi phân vùng riêng biệt lssẽ chỉ sắp xếp tập hợp con của các mục được cung cấp cho nó xargs.

Mặc dù bạn có thể vượt quá giới hạn theo đề xuất của người khác, nhưng vẫn sẽ có giới hạn - và một ngày nào đó, bộ sưu tập JPG của bạn sẽ phát triển lại. Bạn nên chuẩn bị (các) tập lệnh của mình để xử lý số lượng vô hạn ...


Cảm ơn ý tưởng! Đây không phải là một cách giải quyết tồi. Hai cảnh báo: 1. Điều này phá vỡ các thư mục và tên tệp có khoảng trắng trong tên của chúng, vì vậy nó không phải là một thay thế hoàn hảo. 2. Điều đó có gặp phải vấn đề tương tự không Argument list too long, nhưng echothay vì ls, trên các shell echokhông phải là lệnh tích hợp shell? (Có lẽ đó không phải là vấn đề trong hầu hết các hệ vỏ, nên có lẽ điều đó không liên quan.)
DW

1
Vâng, các nhân vật đặc biệt trong tên tập tin là một vấn đề. Đặt cược tốt nhất của bạn là sử dụng findvới -print0vị ngữ - và đưa đầu ra của nó vào xargsvới -0tùy chọn. echolà một shell được tích hợp sẵn và không bị giới hạn dòng lệnh của exec(3).
Mikhail T.
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.