Sao chép danh sách các tập tin


35

Tôi có một danh sách các tệp được phân tách bằng khoảng trắng trong một tệp list.txt. Tôi muốn sao chép chúng vào một thư mục mới.

Tôi đã cố gắng làm:

cp `cat list.txt` new_folder

nhưng nó không hoạt động.

Bạn sẽ làm điều này như thế nào ?

Cập nhật:

Cảm ơn bạn cho tất cả các câu trả lời rất thú vị của bạn. Tôi không yêu cầu nhiều như vậy :)

Sau khi thử giải pháp trên lần thứ hai, có vẻ như đã cpin trợ giúp sử dụng vì thư mục new_folderchưa tồn tại! Xin lỗi, nó có vẻ là một sai lầm ngu ngốc ... Khi tôi tạo thư mục trước đó, nó hoạt động.

Tuy nhiên, tôi đã học được nhiều từ tất cả các câu trả lời và giải pháp của bạn, cảm ơn bạn đã dành thời gian để viết chúng.


Hãy để tôi hiểu một điều rõ ràng: danh sách có tất cả các tên tệp trên một dòng, chỉ cách nhau bởi một khoảng trắng? Hoặc là mỗi tên trên một dòng riêng biệt?
Telemachus

Tất cả trong một vôi, cách nhau bởi một khoảng trống. Giải pháp của Doug đã có hiệu quả :) Cảm ơn bạn đã trả lời.
Klaus

Điều đó thật buồn cười ... Tôi đã thử nghiệm giải pháp của mình với một dòng trong đó mỗi tên nằm trên một dòng riêng biệt.
Doug Harris

"Nó không hoạt động" không có ý nghĩa lắm. Chính xác làm thế nào nó không hoạt động. Việc này ổn với tôi.
Tạm dừng cho đến khi có thông báo mới.

Xin lỗi: nó cho thấy sự giúp đỡ sử dụng cp. Xem cập nhật của tôi ở trên.
Klaus

Câu trả lời:


34

Hãy thử sử dụng xargs:

cat list.txt | xargs -J % cp % new_folder

Cập nhật:

Tôi đã làm điều này trên OS X có phiên bản khác với phiên bản GNU / Linux. Cái xargsxuất phát từ GNU findutils không có -Jnhưng nó cũng -Itương tự (như Dennis Williamson đã chỉ ra trong một bình luận). Phiên bản xargs OS X có cả hai -I-Jcó hành vi hơi khác nhau - hoặc sẽ hoạt động cho câu hỏi ban đầu này.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder

3
Tôi xargskhông có -J-Imà dường như làm điều tương tự. Phiên bản nào xargsvà hệ điều hành / phân phối nào bạn có?
Tạm dừng cho đến khi có thông báo mới.

Tôi đã thử nghiệm điều này trên Mac OS X 10.6 (còn gọi là báo tuyết), vì vậy đó là bất kỳ phiên bản nào của xargs đều được cài đặt với HĐH. Chạy xargs --versiontrả về một thông báo lỗi sử dụng. Đây có thể là phiên bản BSD của xargs. Việc sử dụng -I-Jlà khác nhau tinh tế. Tôi sẽ cập nhật câu trả lời của tôi với các ví dụ được định dạng độc đáo.
Doug Harris

Đúng, tôi đang làm việc với Mac OSX 10.6. Cảm ơn bạn đã đề phòng -J-I:)
Klaus

Đó là một mẹo hay để sử dụng echo để kiểm tra các lệnh của bạn trước khi bạn chạy chúng.
Liam

1
Chỉ sử dụng lệnh trên với các thay đổi cần thiết, làm cách nào để sao chép các tệp cùng với việc tạo thư mục và thư mục con của chúng, được phân tách bằng dấu gạch chéo?
Vicky Dev

54

Không cần catchút nào:

xargs -a list.txt cp -t new_folder

Hoặc sử dụng các tùy chọn dài:

xargs --arg-file=list.txt cp --target-directory=new_folder

Dưới đây là một số phiên bản vỏ. Lưu ý rằng một số biến không được trích dẫn hoặc forcác vòng lặp được sử dụng cụ thể vì OP chỉ định rằng tên tệp được phân cách bằng dấu cách. Một số kỹ thuật này sẽ không hoạt động đối với đầu vào tên tệp trên mỗi dòng trong đó tên tệp chứa khoảng trắng.

Bash:

for file in $(<list.txt); do cp "$file" new_folder; done

hoặc là

cp $(<list.txt) new_folder

sh (hoặc Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

hoặc là

# none here either
while read -r line; do cp $line new_folder; done < list.txt

hoặc là

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

hoặc là

# meow
cp $(cat list.txt) new_folder

câu hỏi noob: tại sao -tcần thiết trong xargs -a list.txt cp -t new_folder?
Yibo Yang

1
@YiboYang: Đây -tlà một lựa chọn của cp. Nó sao chép tất cả các đối số nguồn vào thư mục đích được chỉ định. Ở đây, nó cho phép mục tiêu được chỉ định trước nguồn được thêm bởi xargslệnh.
Tạm dừng cho đến khi có thông báo mới.

Điều này hữu ích nhưng nếu list.txt chứa đường dẫn tệp và thư mục hỗn hợp thì sao? Trong trường hợp đó, lệnh không hoạt động đúng. Nó báo cáo "bỏ thư mục ..." và nếu -R được chỉ định cho lệnh cp thì lỗi "không phải là thư mục" được báo cáo ngay khi gặp tệp đầu tiên trong danh sách.
Bemipefe

7

Tôi đã có một câu trả lời lúng túng quanh đây trước đó, nhưng câu trả lời của Denis nhắc nhở tôi rằng tôi đã bỏ lỡ điều cơ bản nhất. Vì vậy, tôi đã xóa câu trả lời ban đầu của tôi. Nhưng vì không ai nói điều này rất cơ bản, tôi nghĩ rằng đáng để đặt nó ở đây.

Câu hỏi ban đầu là "Tôi có một tệp văn bản với một danh sách các tên tệp được phân tách bằng dấu cách. Làm cách nào tôi có thể sao chép chúng vào một thư mục đích." Lúc đầu, điều này có vẻ phức tạp hoặc phức tạp, bởi vì bạn nghĩ rằng bạn phải trích xuất các mục từ tệp theo cách cụ thể. Tuy nhiên, khi shell xử lý một dòng lệnh, điều đầu tiên nó làm là tách danh sách đối số thành các mã thông báo và (đây là bit không ai nói hoàn toàn) các dấu cách tách biệt . (Dòng mới cũng phân tách mã thông báo, đó là lý do tại sao thử nghiệm của Doug Harris với danh sách được phân tách dòng mới có kết quả tương tự.) Đó là, trình bao mong đợi và có thể xử lý danh sách được phân tách bằng dấu cách.

Vì vậy, tất cả những gì bạn cần làm ở đây là đặt danh sách được phân tách bằng dấu cách (mà bạn đã có) vào đúng vị trí trong lệnh của bạn. Lệnh của bạn là một số biến thể về điều này:

cp file1 file2 file3...file# target

Điều duy nhất là bạn muốn lấy danh sách các tệp từ 1 đến # từ tệp văn bản của mình.

Như Dennis chỉ ra trong nhận xét của anh ấy, nỗ lực ban đầu của bạn ( cpcat list.txt new_folder) đã hoạt động. Tại sao? Bởi vì lệnh nội bộ cat list.txtđược xử lý trước bởi shell và mở rộng thành file1 file2 file3...file#, đó chính xác là những gì shell mong đợi và muốn ở phần đó của lệnh. Nếu nó không hoạt động thì (1) bạn đã mắc lỗi đánh máy hoặc (2) tên tệp của bạn bằng cách nào đó kỳ lạ (chúng có khoảng trắng hoặc các ký tự bất thường khác).

Lý do mà tất cả các câu trả lời của Dennis hoạt động chỉ đơn giản là chúng cung cấp danh sách các tệp cần thiết cpđể làm việc, đặt danh sách đó vào vị trí của nó trong toàn bộ lệnh. Một lần nữa, chính lệnh này là trong cấu trúc:

cp list-of-files target_directory

Thật dễ dàng để thấy tất cả kết hợp với nhau như thế nào trong phiên bản này:

cp $(<list.txt) new_folder

$()làm cho shell chạy lệnh bên trong dấu ngoặc đơn và sau đó thay thế đầu ra của nó tại điểm đó trong dòng lớn hơn. Sau đó, vỏ chạy toàn bộ dòng. Nhân tiện, đây $()là phiên bản hiện đại hơn của những gì bạn đã làm với backticks (`). Tiếp theo: <là một toán tử chuyển hướng tập tin. Nó báo cho shell đổ nội dung của list.txtđầu vào tiêu chuẩn. Vì $()bit được xử lý trước, đây là những gì xảy ra trong các giai đoạn:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Rõ ràng bước 2 chỉ đơn giản là cplệnh bình thường mà bạn muốn.

Tôi nhận ra rằng tôi đã đánh con ngựa này (có lẽ rất chết) rất nhiều, nhưng tôi nghĩ nó đáng để làm. Hiểu chính xác cách shell xử lý một lệnh có thể giúp bạn viết nó tốt hơn và đơn giản hóa rất nhiều. Nó cũng sẽ cho bạn thấy nơi mà các vấn đề có khả năng được che giấu. Trong trường hợp này, ví dụ, câu hỏi đầu tiên của tôi cho bạn nên là về tên tập tin vui hoặc một lỗi đánh máy có thể. Không cần nhào lộn.


@Klaus Bạn rất hoan nghênh. Thành thật mà nói, tôi đã rất khó chịu với chính mình sau khi đọc câu trả lời của Dennis và nhận ra rằng tôi đã bỏ lỡ phần chính của vấn đề. Giải pháp bạn thích là từ đó là tốt.
Telemachus

Đây là một câu trả lời siêu cũ, nhưng nếu bạn cần tạo lại cấu trúc thư mục, bạn cần --parentscờ. Bạn có thể làm cho nó dài dòng với -vmột bản ghi về những gì đã được sao chép. Nếu bạn muốn giữ quyền, bạn cần -ahoặc -pcờ. Ví dụ cp --parents -av $(<list.txt) new_folder. Đây là tất cả giả sử danh sách các tệp của bạn thực sự là tất cả các tệp, ngoài ra bạn cũng có thể cần -rcờ để lặp lại.
dhaupin

@dhaupin Thật ra, OP nói rằng anh ấy đã dùng macOS. Vì vậy, với giá trị của nó, --parentscờ không tồn tại ở đó. Phiên bản (có nguồn gốc BSD) của họ cpchỉ cung cấp các tùy chọn ngắn, không phải tùy chọn dài theo kiểu GNU. Đối với kiểu BSD cp, cờ cho bản sao đệ quy là chữ hoa -R, không phải chữ thường.
Telemachus
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.