List Danh sách đối số quá dài 'trong khi sao chép một số lượng lớn tệp


12

Tôi đang sử dụng lệnh sau:

\cp -uf /home/ftpuser1/public_html/ftparea/*.jpg /home/ftpuser2/public_html/ftparea/

Và tôi đang nhận được lỗi:

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

Tôi cũng đã thử:

ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} /home/ftpuser2/public_html/ftparea/

Vẫn có -bash: / bin / ls: Danh sách đối số quá dài

Có ý kiến ​​gì không?


Tôi đang cố gắng sao chép tất cả các jpg từ 1 thư mục sang thư mục khác nhưng chỉ các tệp mới và các tệp đã được cập nhật.
icelizard

lskhông được thiết kế để làm điều này. Sử dụng find.
Tạm dừng cho đến khi có thông báo mới.

Vấn đề không nằm ở ls, đó là với số lượng đối số mà shell đang truyền cho ls. Bạn sẽ nhận được cùng một lỗi với vi hoặc với bất kỳ lệnh không dựng sẵn nào.
chris

Nhưng lsđặc biệt không được thiết kế để làm điều này: mywiki.wooledge.org/ParsingLs
Tạm dừng cho đến khi có thông báo mới.

Đúng, nhưng trong trường hợp này, lỗi không phải do lỗi phân tích cú pháp với ls, đó là việc chuyển một tỷ đối số cho một quy trình mới xảy ra là ls. Ngoài việc sử dụng ls không phù hợp, nó còn xảy ra va chạm với giới hạn tài nguyên / thiết kế của unix. Trong trường hợp này, bệnh nhân bị đau bụng và gãy chân.
chris

Câu trả lời:


19

* .jpg mở rộng thành một danh sách dài hơn trình bao có thể xử lý. Hãy thử điều này thay thế

find  /home/ftpuser/public_html/ftparea/ -name "*.jpg" -exec cp -uf "{}" /your/destination \;

Tôi đã sử dụng find / home / ftpuser1 / public_html / ftparea / -name "* jpg" -exec cp -uf "{}" / home / ftpuser2 / public_html / ftparea / và gặp lỗi sau: tìm đối số thiếu cho `-exec '
icelizard

Bạn đang thiếu lập luận cuối cùng của cp, người trả lời đã nói với bạn đúng. Kiểm tra lại việc thực hiện của bạn. Lưu ý rằng trong câu trả lời này, dấu chấm trong "* .jpg" bị thiếu, điều này có thể dẫn đến các hành vi sai (ví dụ như một thư mục có tên "myjpg"). Lưu ý rằng điều đó có thể là hoang tưởng nhưng an toàn hơn để chỉ định chặt chẽ những gì bạn sẽ sao chép bằng cách sử dụng tệp -type (ngăn chặn thư mục, liên kết tượng trưng và như vậy sẽ bị ảnh hưởng)
drAlberT

Sau khi kiểm tra kỹ hơn, tôi đã bỏ lỡ để hoàn thành lệnh mà -exec nên thực thi. Tôi ngớ ngẩn quá!
icelizard

@AlberT: cảm ơn vì những cái đầu lại là dấu chấm còn thiếu. Đó là một lỗi đánh máy. Trả lời cập nhật.
Shawn Chin

Không phải là cp không thể xử lý nó. Vỏ không thể.
d -_- b

6

Có một giới hạn tối đa về thời gian một danh sách đối số có thể dành cho các lệnh hệ thống - giới hạn này là dành riêng cho phân phối dựa trên giá trị MAX_ARG_PAGESkhi kernel được biên dịch và không thể thay đổi mà không biên dịch lại kernel.

Do cách xử lý toàn cầu hóa bởi trình bao, điều này sẽ ảnh hưởng đến hầu hết các lệnh hệ thống khi bạn sử dụng cùng một đối số ("* .jpg"). Vì toàn cầu được xử lý bởi shell trước, sau đó được gửi đến lệnh, nên lệnh:

cp -uf *.jpg /targetdir/

về cơ bản là giống với vỏ như thể bạn đã viết:

cp -uf 1.jpg 2.jpg ... n-1.jpg n.jpg /targetdir/

Nếu bạn đang xử lý nhiều jpeg, điều này có thể trở nên khó kiểm soát rất nhanh. Tùy thuộc vào quy ước đặt tên của bạn và số lượng tệp bạn thực sự phải xử lý, bạn có thể chạy lệnh cp trên một tập hợp con khác nhau của thư mục tại một thời điểm:

cp -uf /sourcedir/[a-m]*.jpg /targetdir/
cp -uf /sourcedir/[n-z]*.jpg /targetdir/

Điều này có thể hoạt động, nhưng chính xác hiệu quả của nó sẽ dựa trên mức độ bạn có thể chia danh sách tệp của mình thành các khối có thể kết nối thuận tiện.

Toàn cầu Tôi thích từ đó.

Một số lệnh, chẳng hạn như findxargs , có thể xử lý danh sách tệp lớn mà không tạo danh sách đối số có kích thước lớn.

find /sourcedir/ -name '*.jpg' -exec cp -uf {} /targetdir/ \;

Đối số -exec sẽ chạy phần còn lại của dòng lệnh một lần cho mỗi tệp được tìm thấy bằng cách tìm , thay thế {} bằng mỗi tên tệp được tìm thấy. Vì lệnh cp chỉ được chạy trên một tệp tại một thời điểm, giới hạn danh sách đối số không phải là vấn đề.

Điều này có thể chậm do phải xử lý từng tệp riêng lẻ. Sử dụng xargs có thể cung cấp một giải pháp hiệu quả hơn:

find /sourcedir/ -name '*.jpg' -print0 | xargs -0 cp -uf -t /destdir/

xargs có thể lấy danh sách tệp đầy đủ do find cung cấp và chia nó thành các danh sách đối số có kích thước có thể quản lý và chạy cp trên mỗi danh sách con đó.

Tất nhiên, cũng có khả năng chỉ biên dịch lại kernel của bạn, đặt giá trị lớn hơn cho MAX_ARG_PAGES. Nhưng biên dịch lại kernel là công việc nhiều hơn tôi sẵn sàng giải thích trong câu trả lời này.


Tôi không biết tại sao điều này đã được bỏ phiếu. Đó là câu trả lời duy nhất dường như đang giải thích tại sao điều này xảy ra. Có lẽ bởi vì bạn đã không đề xuất sử dụng xargs như một tối ưu hóa?
chris

được thêm vào trong giải pháp xargs, nhưng tôi vẫn lo lắng các downvote là do có gì đó sai trái rõ ràng trong chi tiết của tôi và không ai muốn nói cho tôi biết đó là gì. :(
goldPseudo

xargsdường như hiệu quả hơn nhiều, vì kết quả số lượng lệnh gọi nhỏ hơn nhiều. Trong trường hợp của tôi, tôi thấy hiệu suất tốt hơn 6-12 lần khi sử dụng argskhi đó khi sử dụng -execgiải pháp với số lượng tệp ngày càng tăng là hiệu quả tăng lên.
Jan Vlcinsky

3

Điều đó xảy ra vì biểu thức ký tự đại diện ( *.jpg) của bạn vượt quá giới hạn độ dài đối số dòng lệnh khi được mở rộng (có thể do bạn có nhiều tệp .jpg bên dưới /home/ftpuser/public_html/ftparea).

Có một số cách để vượt qua giới hạn đó, như sử dụng findhoặc xargs. Hãy xem bài viết này để biết thêm chi tiết về cách làm điều đó.


+1 cho tài nguyên bên ngoài tốt về chủ đề.
viam0Zah

3

Như GoldPseudo đã nhận xét, có giới hạn về số lượng đối số bạn có thể vượt qua cho một quá trình bạn sinh ra. Xem câu trả lời của anh ấy cho một mô tả tốt về tham số đó.

Bạn có thể tránh vấn đề bằng cách không vượt qua quá trình quá nhiều đối số hoặc bằng cách giảm số lượng đối số bạn đang truyền.

Một vòng lặp for trong shell, find và ls, grep và một vòng lặp while đều làm điều tương tự trong tình huống này -

for file in /path/to/directory/*.jpg ; 
do
  rm "$file"
done

find /path/to/directory/ -name '*.jpg' -exec rm  {} \;

ls /path/to/directory/ | 
  grep "\.jpg$" | 
  while
    read file
  do
    rm "$file"
  done

tất cả đều có một chương trình đọc thư mục (chính shell, find và ls) và một chương trình khác thực sự lấy một đối số cho mỗi lần thực hiện và lặp qua toàn bộ danh sách các lệnh.

Bây giờ, điều này sẽ chậm vì rm cần được rẽ nhánh và được thực thi cho mỗi tệp khớp với mẫu * .jpg.

Đây là nơi xargs phát huy tác dụng. xargs lấy đầu vào tiêu chuẩn và với mỗi N (đối với freebsd, theo mặc định là 5000), nó sinh ra một chương trình với N đối số. xargs là tối ưu hóa các vòng lặp ở trên vì bạn chỉ cần rẽ nhánh các chương trình 1 / N để lặp lại toàn bộ tập tin đọc các đối số từ dòng lệnh.



1

Toàn cầu '*' đang mở rộng thành quá nhiều tên tệp. Thay vào đó, hãy sử dụng find / home / ftpuser / public_html -name '* .jpg'.


Tìm và lặp lại * dẫn đến cùng một đầu ra - khóa ở đây là sử dụng xargs không chỉ chuyển tất cả 1 tỷ đối số dòng lệnh cho lệnh shell đang cố gắng rẽ nhánh.
chris

echo * sẽ thất bại nếu có quá nhiều tệp, nhưng find sẽ thành công. Ngoài ra, sử dụng find -exec với + tương đương với sử dụng xargs. (Tuy nhiên, không phải tất cả đều tìm thấy hỗ trợ +)
William Pursell

1

Sử dụng +tùy chọn để find -exectăng tốc độ hoạt động rất nhiều.

find  /home/ftpuser/public_html/ftparea/ -name "*jpg" -exec cp -uf -t /your/destination "{}" +

Các +tùy chọn đòi hỏi {}phải tranh luận cuối cùng để sử dụng -t /your/destination(hoặc --target-directory=/your/destination) tùy chọn để cplàm cho nó hoạt động.

Từ man find:

lệnh -exec {} +

          This  variant  of the -exec action runs the specified command on  
          the selected files, but the command line is built  by  appending  
          each  selected file name at the end; the total number of invoca  
          tions of the command will  be  much  less  than  the  number  of  
          matched  files.   The command line is built in much the same way  
          that xargs builds its command lines.  Only one instance of  ‘{}’  
          is  allowed  within the command.  The command is executed in the  
          starting directory.

Chỉnh sửa : sắp xếp lại các đối số để cp


Tôi đang tìm thấy: thiếu đối số cho `-exec '/ home / ftpuser1 / public_html / ftparea / -name' * jpg '-exec cp -uf" {} "/ home / ftpuser2 / public_html / ftparea / +
icelizard

Tôi sắp xếp lại các đối số cpđể sửa lỗi đó.
Tạm dừng cho đến khi có thông báo mới.

1

Có vẻ như bạn có quá nhiều *.jpgtệp trong thư mục đó để đặt tất cả chúng vào dòng lệnh cùng một lúc. Bạn có thể thử:

find /home/ftpuser/public_html/ftparea1 -name '*.jpg' | xargs -I {} cp -uf {} /home/ftpuser/public_html/ftparea2/

Bạn có thể cần kiểm tra man xargsviệc triển khai của mình để xem liệu công -Itắc có đúng với hệ thống của bạn không.

Trên thực tế, bạn có thực sự có ý định sao chép các tệp đó vào cùng một vị trí mà chúng đã ở không?


xin lỗi đây là hai thư mục khác nhau nên là ftpuser1 và ftpuser2
icelizard

Chỉ cần thử điều này: ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} / home / ftpuser2 / public_html / ftparea / Vẫn có -bash: / bin / ls: Danh sách đối số quá dài
icelizard

Ồ, bạn hoàn toàn đúng, tất nhiên lssẽ có cùng một vấn đề! Tôi đã đổi thành findsẽ không.
Greg Hewgill

0

Chuyển đến thư mục

cd /home/ftpuser1/public_html/

và thực hiện như sau:

cp -R ftparea/ /home/ftpuser2/public_html/

Theo cách này nếu thư mục 'ftparea' có các thư mục con, đây có thể là một hiệu ứng tiêu cực nếu bạn chỉ muốn các tệp '* .jpg' từ nó, nhưng nếu không có bất kỳ thư mục con nào, cách tiếp cận này chắc chắn sẽ nhanh hơn nhiều sử dụng find và xargs

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.