Bộ lọc Rsync: chỉ sao chép một mẫu


128

Tôi đang cố gắng tạo một thư mục chứa tất cả và chỉ các tệp PDF của tôi được biên dịch từ LaTeX. Tôi thích giữ mỗi dự án trong một thư mục riêng biệt, tất cả được đặt trong một thư mục lớn được gọi LaTeX. Vì vậy, tôi đã cố gắng chạy:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

cần tìm tất cả các tệp pdf ~/LaTeX/và chuyển chúng vào thư mục đầu ra. Điều này không hoạt động. Nó cho tôi biết nó không tìm thấy kết quả nào cho " *.pdf". Nếu tôi rời khỏi bộ lọc này, lệnh sẽ liệt kê tất cả các tệp trong tất cả các thư mục dự án trong LaTeX. Vì vậy, đó là một vấn đề với bộ lọc * .pdf. Tôi đã thử thay thế ~/bằng đường dẫn đầy đủ đến thư mục nhà của tôi, nhưng điều đó không có kết quả.

Tôi đang sử dụng zsh. Tôi đã thử làm điều tương tự trong bash và thậm chí với bộ lọc liệt kê mọi tệp duy nhất trong mỗi thư mục con ... Chuyện gì đang xảy ra ở đây?

Tại sao rsync không hiểu bộ lọc chỉ pdf của tôi?


ĐỒNG Ý. Vì vậy, cập nhật: Không tôi đang cố gắng

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

Và điều này cho tôi toàn bộ danh sách tập tin. Tôi đoán bởi vì mọi thứ phù hợp với mẫu đầu tiên ...


uh, bạn có vẻ đúng ... Tôi nghĩ rằng câu trả lời của tôi (sử dụng **mẫu của zsh ) nên hoạt động, mặc dù.
Marcel Promotionberg

Câu trả lời:


248

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync sao chép (các) nguồn đến đích. Nếu bạn chuyển *.pdfdưới dạng nguồn, shell sẽ mở rộng danh sách này sang danh sách các tệp có .pdfphần mở rộng trong thư mục hiện tại. Không có giao dịch đệ quy xảy ra vì bạn không vượt qua bất kỳ thư mục nào dưới dạng nguồn.

Vì vậy, bạn cần phải chạy rsync -a ~/LaTeX/ ~/Output/, nhưng với một bộ lọc để nói với rsync chỉ sao chép .pdfcác tệp. Các quy tắc bộ lọc của Rupync có vẻ khó xử khi bạn đọc hướng dẫn, nhưng bạn có thể xây dựng nhiều ví dụ chỉ bằng một vài quy tắc đơn giản.

  • Bao gồm và loại trừ:

    • Loại trừ các tệp theo tên hoặc theo vị trí rất dễ dàng : --exclude=*~, --exclude=/some/relative/location(liên quan đến đối số nguồn, ví dụ: loại trừ này ~/LaTeX/some/relative/location).
    • Nếu bạn chỉ muốn khớp một vài tệp hoặc vị trí, hãy bao gồm chúng, bao gồm mọi thư mục dẫn đến chúng (ví dụ với --include=*/), sau đó loại trừ phần còn lại với --exclude='*'. Điều này là do:
    • Nếu bạn loại trừ một thư mục, điều này sẽ loại trừ mọi thứ bên dưới nó. Các tập tin loại trừ sẽ không được xem xét ở tất cả.
    • Nếu bạn bao gồm một thư mục, điều này không tự động bao gồm nội dung của nó. Trong các phiên bản gần đây, --include='directory/***'sẽ làm điều đó.
    • Đối với mỗi tệp, quy tắc khớp đầu tiên được áp dụng (và mọi thứ không bao giờ khớp được bao gồm).
  • Mẫu, mô hình, kiểu; khuôn mẫu:

    • Nếu một mẫu không chứa a /, nó sẽ áp dụng cho thư mục sans tên tệp.
    • Nếu một mô hình kết thúc bằng /, nó chỉ áp dụng cho các thư mục.
    • Nếu một mẫu bắt đầu bằng /, nó áp dụng cho toàn bộ đường dẫn từ thư mục được truyền dưới dạng đối số rsync.
    • *bất kỳ chuỗi con nào của một thành phần thư mục (nghĩa là không bao giờ khớp /); **phù hợp với bất kỳ chuỗi con đường dẫn.
  • Nếu một đối số nguồn kết thúc bằng a /, nội dung của nó sẽ được sao chép ( rsync -r a/ btạo b/foocho mọi a/foo). Nếu không, chính thư mục được sao chép ( rsync -r a btạo b/a).


Vì vậy, ở đây chúng ta cần bao gồm *.pdf, bao gồm các thư mục chứa chúng và loại trừ mọi thứ khác.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Lưu ý rằng điều này sao chép tất cả các thư mục, ngay cả những thư mục không chứa tệp hoặc thư mục con phù hợp chứa một thư mục. Điều này có thể tránh được với --prune-empty-dirstùy chọn (nó không phải là một giải pháp phổ quát vì sau đó bạn không thể sao chép một thư mục ngay cả bằng cách khớp nó một cách rõ ràng, nhưng đó là một yêu cầu hiếm gặp).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Ngược lại với giải pháp của tôi (sử dụng **mẫu của zsh ), điều này tạo lại cấu trúc thư mục trong thư mục đích. Tôi không chắc liệu đây có phải là điều OP muốn không ...
Marcel Promotionberg

Tôi muốn chỉ bao gồm một thư mục và loại trừ phần còn lại của tất cả các thư mục trong /etc/lsyncd/lsyncd.conf.luatệp. Có ý kiến ​​gì không?
Dhaduk Mitesh

@DhadukMitesh Tôi không quen với lsyncd. Bạn nên hỏi điều này như một câu hỏi mới.
Gilles

25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

Mặc định là bao gồm mọi thứ, vì vậy bạn phải loại trừ rõ ràng mọi thứ sau khi bao gồm các tệp bạn muốn chuyển. Xóa --dry-run để thực sự chuyển các tệp.

Nếu bạn bắt đầu với:

--exclude '*' --include '*.pdf'

Sau đó, sự phù hợp tham lam sẽ loại trừ mọi thứ ngay lập tức.

Nếu bạn cố gắng:

--include '*.pdf' --exclude '*' 

Sau đó, chỉ các tệp pdf trong thư mục cấp cao nhất sẽ được chuyển. Nó sẽ không theo bất kỳ thư mục nào, vì những thư mục đó bị loại trừ bởi '*'.


2
Kể từ 2014/03/17, đây là câu trả lời tốt nhất, vì nó giải quyết chính xác câu hỏi áp phích ban đầu . Hãy bỏ phiếu lên! Nếu bạn thêm --prune-empty-dirs(hoặc phím tắt -m), bạn thậm chí còn dành cho mình nhiều thư mục trống ở đích, ngoại trừ tất nhiên bạn muốn chúng như một lời nhắc hoặc kế hoạch chi tiết cấu trúc.
porg

1
Câu trả lời hay nhất, --include = "* /" là chìa khóa.
Martin Konicek

Tôi muốn chỉ bao gồm một thư mục và loại trừ phần còn lại của tất cả các thư mục trong /etc/lsyncd/lsyncd.conf.luatệp. Có ý kiến ​​gì không?
Dhaduk Mitesh

15

Nếu bạn sử dụng một mẫu như thế *.pdf, shell thì sẽ mở rộng mô hình đó, tức là nó thay thế mẫu đó bằng tất cả các kết quả khớp trong thư mục hiện tại. Lệnh bạn đang chạy (trong trường hợp này là rsync) không biết thực tế là bạn đã cố sử dụng một mẫu.

Khi bạn đang sử dụng zsh , có một giải pháp dễ dàng: Mặc dù vậy, **mẫu có thể được sử dụng để khớp với các thư mục theo cách đệ quy. Thử đi:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/

Điều đó sẽ không sao chép tất cả các tệp pdf từ một nơi nào đó trong thư mục hiện tại mọi thứ từ ~ / LaTeX / đến ~ / Đầu ra?
SamB

Tôi đoán bạn có nghĩa là rsync -avn ~/LaTeX/**/*.pdf ~/Output, nhưng giải pháp với --includekhả năng mở rộng hơn dù sao.
Adam Byrtek

Xin lỗi, đã sửa lệnh tôi đã nhập nhầm ... Tôi đồng ý rằng lệnh bao gồm (trong phiên bản của SamB) tốt hơn, mặc dù nó phức tạp và cụ thể hơn một chút đối với rsync trong khi cũng **có thể trở nên tiện dụng trong các tình huống khác.
Marcel Promotionberg

1
Bash 4 đã áp dụng tính năng tương tự. Ồ, và bạn không cần rsync ở đây, cp sẽ làm. Trên một số hệ thống, nếu có nhiều tập tin, sẽ giúp thực hiện cd ~/Latex && cp -p **/*.pdf ~/Outputđể tránh một dòng lệnh lỗi quá dài lỗi lỗi.
Gilles

1
Lưu ý rằng các mẫu của rsync được sử dụng trong các bộ lọc bao gồm và loại trừ cũng có ** thực hiện điều tương tự. Bạn có thể thoát * khỏi các shell khác bằng cách đặt chúng vào dấu ngoặc kép.
Dan Pritts 4/2/2015

13

Bạn có thể sử dụng findvà một danh sách trung gian các tệp ( files_to_copy) để giải quyết vấn đề của bạn. Hãy chắc chắn rằng bạn đang ở trong thư mục nhà của bạn, sau đó:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Đã thử nghiệm với Bash.


Tôi nghĩ rằng find là giải pháp mạnh mẽ nhất, nhưng tôi sẽ chọn sử dụng -exectùy chọn find hoặc sử dụng xargs. Một cái gì đó như:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D

Vâng ... tôi cũng khuyên bạn nên tìm ... mặc dù tôi tưởng tượng rsync phải có thể làm điều này.
gabe.

Đây cũng là một giải pháp gọn gàng cho một vấn đề khó khăn hơn: có lẽ tôi có thể sử dụng điều này để loại trừ các tệp có lớp tài liệu standalonehoặc không có .textệp có cùng tên, vì đây sẽ là những hình ảnh có trong một số tài liệu ...
Seamus

2
tùy chọn rsync --files-fromchấp nhận đọc từ stdin. Điều này sẽ hoạt động find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero

9

Đánh giá theo phần "INCLUDE / EXCLUDE PATULN RULES" của trang này , cách để làm điều này là

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

Sự khác biệt quan trọng giữa câu trả lời này và câu trả lời của kbrd là --include="*/"cờ, thông báo cho rsync đi trước và sao chép bất kỳ thư mục nào nó tìm thấy, bất kể chúng được đặt tên là gì. Điều này là cần thiết bởi vì rsync sẽ không tái diễn vào thư mục con trừ khi nó được hướng dẫn sao chép thư mục con đó.

Ngoài ra, lưu ý rằng dấu ngoặc kép ngăn shell cố gắng mở rộng các mẫu thành tên tệp so với thư mục hiện tại và thực hiện một trong các thao tác sau:

  1. Thành công và làm rối bộ lọc của bạn (không quá có khả năng ở giữa một lá cờ như thế, mặc dù bạn thực sự không bao giờ biết khi nào ai đó sẽ tạo một tệp có tên --include=foo.pdf...)

  2. Không thành công và có khả năng tạo ra lỗi thay vì chạy lệnh (như bạn đã phát hiện ra zsh theo mặc định).


Vì vậy, điều này sẽ chỉ sao chép các tệp PDF và cấu trúc thư mục, trong khi kbrd sẽ sao chép các tệp, nhưng bỏ qua cấu trúc?
Seamus

1
Hừm. Điều này thực sự dường như vẫn cố gắng và sao chép mọi thứ, tôi đoán bởi vì đó là những gì nó làm mà không có bộ lọc, vì vậy, includenhững thứ bổ sung đã có trong đó không thay đổi bất cứ điều gì. Nếu bạn hiểu ý tôi là ...
Seamus

7
Bạn cần --exclude="*"sau --include="*.pdf", hoặc điều này sẽ chuyển tất cả mọi thứ.
jmanning2k

@ jmanning2k: À. Tốt để biết!
SamB

4

Còn cái này thì sao:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/

Không, man rsyncđặt bộ lọc sau các tùy chọn và trước nguồn / định mệnh. Tôi đã thử cách này và nó không hoạt động
Seamus

Cách của bạn tìm thấy các tệp .pdf trong thư mục hiện tại, nhưng không phải đệ quy, như tôi muốn. ( atùy chọn dành cho lưu trữ và trong số những thứ khác, nó làm cho việc sao chép được đệ quy.
Seamus

1
Ôi, xấu quá. Tôi cập nhật câu trả lời của tôi.
kbyrd

+1 vì quá gần gũi và cho tôi manh mối về cách tìm tài liệu liên quan trong trang hướng dẫn. (Hy vọng tôi thậm chí đã hiểu đúng. :-)
SamB

3

Đây là một cái gì đó nên làm việc mà không cần sử dụng find. Sự khác biệt từ các câu trả lời đã được đăng là thứ tự của các quy tắc lọc. Các quy tắc lọc trong lệnh rsync hoạt động rất giống các quy tắc iptable, quy tắc đầu tiên mà tệp khớp với là quy tắc được sử dụng. Từ trang hướng dẫn :

Khi danh sách các tệp / thư mục cần truyền được tạo, rsync sẽ kiểm tra lần lượt từng tên được chuyển theo danh sách các mẫu bao gồm / loại trừ và mẫu phù hợp đầu tiên được thực hiện: nếu đó là mẫu loại trừ, thì tệp đó là bỏ qua; nếu nó là một mẫu bao gồm thì tên tệp đó không bị bỏ qua; nếu không tìm thấy mẫu phù hợp thì tên tệp sẽ không bị bỏ qua.

Vì vậy, bạn cần một lệnh như sau:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Lưu ý mẫu "**. Pdf". Theo trang nam :

nếu mẫu chứa a / (không tính dấu /) hoặc "**", thì mẫu đó được khớp với tên đường dẫn đầy đủ, bao gồm mọi thư mục hàng đầu. Nếu mẫu không chứa / hoặc "**", thì nó chỉ được khớp với thành phần cuối cùng của tên tệp. (Hãy nhớ rằng thuật toán được áp dụng đệ quy để "tên tệp đầy đủ" thực sự có thể là bất kỳ phần nào của đường dẫn từ thư mục bắt đầu trở xuống

Trong thử nghiệm nhỏ của tôi, điều này không hoạt động đệ quy xuống cây thư mục và chỉ chọn các tệp pdf.


Làm thế nào chính xác bạn đã kiểm tra? Theo hiểu biết của tôi về tài liệu và xác minh thử nghiệm của tôi, lệnh của bạn chỉ nên sao chép *.pdftrong thư mục toplevel (chứ không phải ~/LaTeX/foo/bar.pdf).
Gilles

@Gilles Crud. Bạn đúng rồi. Tôi thề tôi đã thử nghiệm cái này và nó đã hoạt động, nhưng dường như tôi không thể tạo lại nó. Và bây giờ tôi thực sự đọc trang người đàn ông mà tôi đã trích dẫn, điều đó có nghĩa là nó không hoạt động. Càu nhàu
Steven D

1
Vâng, tôi đã tìm ra nơi thử nghiệm của tôi là sai. "Thử nghiệm nhỏ" của tôi là trên một thư mục có các tệp .tex và .pdf của riêng tôi. Sau đó tôi đã tạo một thư mục con "test" và test.pdf và test.tex trong thư mục con đó. Tuy nhiên, tôi đã không nhận thấy rằng có một test.pdf trong thư mục cấp cao nhất của tôi, có thể là do một thử nghiệm LaTeX nhanh chóng mà tôi đã làm.
Steven D

Tôi vẫn không hiểu **. Sẽ là tốt đẹp để có ví dụ về nó. ;)
buhtz

2

Đây là giải pháp ưa thích của tôi:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

Các findlệnh là dễ hiểu hơn bao gồm / loại trừ quy tắc của rsync:-)

Nếu bạn chỉ muốn sao chép các tập tin pdf, chỉ cần thay đổi .jpgthành.pdf

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.