Có 3 điểm chính cần lưu ý khi gặp Argument list too long
lỗi:
Độ dài của các đối số dòng lệnh bị giới hạn bởi ARG_MAX
biến, theo định nghĩa POSIX là "... [m] độ dài tối đa của đối số đối với các hàm exec bao gồm dữ liệu môi trường" (nhấn mạnh thêm) ". Đó là khi shell thực thi lệnh không -built-it lệnh, nó phải gọi một trong số đó exec()
để sinh ra quá trình của lệnh đó và đó là nơi ARG_MAX
bắt đầu hoạt động. Ngoài ra, tên hoặc đường dẫn đến chính lệnh (ví dụ, /bin/echo
) đóng vai trò.
Các lệnh dựng sẵn của Shell được thực thi bằng shell, có nghĩa là shell không sử dụng exec()
họ các hàm và do đó không bị ảnh hưởng bởi ARG_MAX
biến.
Một số lệnh nhất định, chẳng hạn như xargs
và find
nhận thức được ARG_MAX
biến và liên tục thực hiện các hành động theo giới hạn đó
Từ những điểm trên và như thể hiện trong câu trả lời xuất sắc của Kusalananda về câu hỏi liên quan, điều Argument list too long
này cũng có thể xảy ra khi môi trường lớn. Vì vậy, xem xét rằng mỗi môi trường của người dùng có thể khác nhau và kích thước đối số tính theo byte có liên quan, thật khó để đưa ra một số tệp / đối số duy nhất.
Làm thế nào để xử lý lỗi như vậy?
Điều quan trọng là không tập trung vào số lượng tệp, mà tập trung vào việc lệnh bạn sẽ sử dụng có liên quan đến exec()
họ chức năng và tiếp tuyến - không gian ngăn xếp.
Sử dụng vỏ tích hợp
Như đã thảo luận trước đây, các vỏ tích hợp có khả năng miễn dịch ARG_MAX
giới hạn, đó là những thứ như for
vòng lặp, while
vòng lặp, tích hợp echo
và tích hợp printf
- tất cả những thứ đó sẽ hoạt động đủ tốt.
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done
Về câu hỏi liên quan về việc xóa các tập tin, có một giải pháp như sau:
printf '%s\0' *.jpg | xargs -0 rm --
Lưu ý rằng điều này sử dụng tích hợp sẵn của shell printf
. Nếu chúng ta gọi bên ngoài printf
, điều đó sẽ liên quan exec()
, do đó sẽ thất bại với số lượng lớn đối số:
$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long
mảng bash
Theo câu trả lời của jlliagre, bash
không áp đặt các giới hạn cho các mảng, do đó, việc xây dựng các tên tệp và sử dụng các lát trên mỗi vòng lặp cũng có thể được thực hiện, như thể hiện trong câu trả lời của danjpreron :
files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do
cp -t /path/to/new_dir/ "${files[@]:I:1000}"
done
Điều này, tuy nhiên, có giới hạn là bash cụ thể và không POSIX.
Tăng không gian ngăn xếp
Đôi khi bạn có thể thấy mọi người đề nghị tăng không gian ngăn xếp với ulimit -s <NUM>
; trên Linux ARG_MAX giá trị là 1/4 không gian ngăn xếp cho mỗi chương trình, có nghĩa là tăng không gian ngăn xếp tăng tỷ lệ không gian cho các đối số.
# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $(( $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304
Theo câu trả lời của Franck Dernoncourt , trích dẫn Tạp chí Linux, người ta cũng có thể biên dịch lại nhân Linux với giá trị lớn hơn cho các trang bộ nhớ tối đa cho các đối số, tuy nhiên, đó là công việc nhiều hơn cần thiết và mở ra tiềm năng khai thác như đã nêu trong bài báo Tạp chí Linux được trích dẫn.
Tránh vỏ
Một cách khác, là sử dụng python
hoặc python3
đi kèm theo mặc định với Ubuntu. Ví dụ python + here-doc bên dưới, là thứ mà cá nhân tôi đã sử dụng để sao chép một thư mục lớn các tệp ở đâu đó trong phạm vi 40.000 mục:
$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
> if os.path.isfile(f):
> shutil.copy(f,'./newdir/')
> EOF
Đối với truy cập đệ quy, bạn có thể sử dụng os.walk .
Xem thêm: