Filtr Rsync: kopiowanie tylko jednego wzorca


128

Próbuję utworzyć katalog, w którym będą przechowywane wszystkie i tylko moje pliki PDF skompilowane z LaTeX. Lubię trzymać każdy projekt w osobnym folderze, wszystkie w dużym folderze o nazwie LaTeX. Więc próbowałem uruchomić:

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

które powinny znaleźć wszystkie pliki pdf ~/LaTeX/i przenieść je do folderu wyjściowego. To nie działa Mówi mi, że nie znaleziono dopasowań dla „ *.pdf”. Jeśli pominę ten filtr, polecenie wyświetla listę wszystkich plików we wszystkich folderach projektu w LaTeX. Jest to problem z filtrem * .pdf. Próbowałem zastąpić ~/pełną ścieżką do mojego katalogu domowego, ale to nie przyniosło efektu.

Używam zsh. Próbowałem zrobić to samo w bash, a nawet z filtrem, który wyświetlał każdy pojedynczy plik w każdym podkatalogu ... Co się tutaj dzieje?

Dlaczego rsync nie rozumie mojego filtru tylko w formacie PDF?


DOBRZE. Więc zaktualizuj: Nie, próbuję

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

A to daje mi całą listę plików. Chyba dlatego, że wszystko pasuje do pierwszego wzoru ...


Wygląda na to, że masz rację ... Myślę, że moja odpowiedź (używając **wzorca Zsh ) powinna jednak działać.
— Marcel Stimberg

Odpowiedzi:


248

TL, DR:

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

Rsync kopiuje źródło (źródła) do miejsca docelowego. Jeśli przekażesz *.pdfjako źródła, powłoka rozwija to do listy plików z .pdfrozszerzeniem w bieżącym katalogu. Nie dzieje się żadne przechodzenie rekurencyjne, ponieważ nie przekazałeś żadnego katalogu jako źródła.

Musisz więc uruchomić rsync -a ~/LaTeX/ ~/Output/, ale z filtrem, który każe rsync kopiować .pdftylko pliki. Reguły filtrowania Rsync mogą wydawać się zniechęcające podczas czytania instrukcji, ale możesz zbudować wiele przykładów za pomocą kilku prostych reguł.

  • Włączenia i wyłączenia:

    • Wykluczanie plików według nazwy lub lokalizacji jest proste: --exclude=*~, --exclude=/some/relative/location(w odniesieniu do argumentu źródłowego, np Wyklucza ~/LaTeX/some/relative/location).
    • Jeśli chcesz dopasować tylko kilka plików lub lokalizacji, dołącz je, dołącz każdy katalog prowadzący do nich (na przykład za pomocą --include=*/), a następnie wyklucz resztę za pomocą --exclude='*'. To dlatego, że:
    • Wykluczenie katalogu wyklucza wszystko poniżej. Wykluczone pliki w ogóle nie będą brane pod uwagę.
    • Jeśli dołączasz katalog, nie obejmuje to automatycznie jego zawartości. W najnowszych wersjach --include='directory/***'zrobi to.
    • Do każdego pliku ma zastosowanie pierwsza reguła dopasowania (i dołączane jest wszystko, co nigdy nie jest dopasowane).
  • Wzory:

    • Jeśli wzorzec nie zawiera /, odnosi się do nazwy pliku w katalogu sans.
    • Jeśli wzorzec kończy się na /, odnosi się tylko do katalogów.
    • Jeśli wzorzec zaczyna się od /, dotyczy całej ścieżki z katalogu, który został przekazany jako argument rsync.
    • *dowolny podciąg jednego komponentu katalogu (tzn. nigdy nie pasuje /); **dopasowuje dowolny podciąg ścieżki.
  • Jeśli argument źródłowy kończy się na a /, jego zawartość jest kopiowana ( rsync -r a/ btworzona b/foodla każdego a/foo). W przeciwnym razie sam katalog jest kopiowany ( rsync -r a btworzy b/a).


Dlatego tutaj musimy uwzględnić *.pdf, uwzględnić katalogi zawierające je i wykluczyć wszystko inne.

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

Zauważ, że powoduje to skopiowanie wszystkich katalogów, nawet tych, które nie zawierają pasującego pliku lub podkatalogu zawierającego jeden. Można tego uniknąć dzięki tej --prune-empty-dirsopcji (nie jest to rozwiązanie uniwersalne, ponieważ nie można wówczas skopiować katalogu, nawet poprzez jawne dopasowanie go, ale jest to rzadkie wymaganie).

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

W przeciwieństwie do mojego rozwiązania (przy użyciu **wzorca zsh ), to odtwarza strukturę katalogów w docelowym katalogu. Nie jestem pewien, czy tego właśnie chce OP…
— Marcel Stimberg,

Chcę dołączyć tylko jeden katalog i wykluczyć resztę całego katalogu w /etc/lsyncd/lsyncd.conf.luapliku. Masz jakiś pomysł?
— Dhaduk Mitesh

@DhadukMitesh Nie znam lsyncd. Powinieneś zadać to jako nowe pytanie.
— Gilles

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

Domyślnie wszystko obejmuje, więc musisz jawnie wykluczyć wszystko po dołączeniu plików, które chcesz przenieść. Usuń --dry-run, aby faktycznie przesłać pliki.

Jeśli zaczniesz od:

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

Chciwe dopasowanie wykluczy wszystko od razu.

Jeśli spróbujesz:

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

Następnie przesyłane będą tylko pliki pdf w folderze najwyższego poziomu. Nie będzie podążał za żadnymi katalogami, ponieważ są one wykluczone przez „*”.


2
Na dzień 17.03.2014 jest to najlepsza odpowiedź, ponieważ dokładnie rozwiązuje oryginalne pytanie dotyczące plakatów . Proszę zagłosować! Jeśli dodasz --prune-empty-dirs(lub skrót -m), zaoszczędzisz sobie nawet wiele pustych katalogów w miejscu docelowym, z tym wyjątkiem, że chcesz je jako przypomnienie lub schemat strukturalny.
— porg

1
Najlepsza odpowiedź, --include = „* /” jest kluczem.
— Martin Konicek,

Chcę dołączyć tylko jeden katalog i wykluczyć resztę całego katalogu w /etc/lsyncd/lsyncd.conf.luapliku. Masz pomysł?
— Dhaduk Mitesh

15

Jeśli użyjesz wzorca podobnego *.pdf, powłoka „rozszerzy” ten wzorzec, tzn. Zastąpi wzorzec wszystkimi dopasowaniami w bieżącym katalogu. Uruchamiane polecenie (w tym przypadku rsync) nie wie o tym, że próbowałeś użyć wzorca.

W przypadku korzystania z zsh istnieje jednak proste rozwiązanie: **wzorca można użyć do rekurencyjnego dopasowywania folderów. Spróbuj tego:

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

Czy nie skopiowałoby to wszystkich plików pdf z gdzieś w bieżącym katalogu i wszystkiego od ~ / LaTeX / do ~ / Output?
— SamB

Chyba miałeś na myśli rsync -avn ~/LaTeX/**/*.pdf ~/Output, ale rozwiązanie z i tak --includejest bardziej skalowalne.
— Adam Byrtek,

Przepraszamy, poprawiłem polecenie, które wpisałem w pośpiechu ... Zgadzam się, że polecenie włączania (w wersji SamB) jest lepsze, choć jest nieco bardziej skomplikowane i specyficzne dla rsync, podczas gdy **może się przydać także w innych sytuacjach.
— Marcel Stimberg,

1
Bash 4 przyjął tę samą funkcję. Och, i nie potrzebujesz tutaj rsync, cp zrobi to. W niektórych systemach, jeśli jest dużo plików, pomaga to cd ~/Latex && cp -p **/*.pdf ~/Outputuniknąć błędu „zbyt długiego wiersza poleceń”.
— Gilles

1
Zauważ, że wzorce rsync używane w filtrach dołączania i wykluczania mają również **, który robi to samo. Możesz uciec * od innych powłok, umieszczając je w cudzysłowie.
— Dan Pritts

13

Aby rozwiązać problem, możesz użyć findpośredniej listy plików ( files_to_copy). Upewnij się, że jesteś w swoim katalogu domowym, a następnie:

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

Testowane z Bash.


Myślę, że find jest najsolidniejszym rozwiązaniem, ale wybrałbym użycie -execopcji find lub użycie xargs. Coś w stylu:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
— Steven D

Tak ... Proponuję również znaleźć ... choć wyobrażam sobie, że rsync musi być w stanie to zrobić.
— Gabe.

Jest to również dobre rozwiązanie trudniejszego problemu: prawdopodobnie mógłbym użyć tego do wykluczenia plików, których klasa dokumentów jest standalonelub nie ma .texpliku o tej samej nazwie, ponieważ będą to obrazy zawarte w niektórych dokumentach ...
— Seamus

2
Opcja rsync --files-fromakceptuje odczyt ze standardowego wejścia. To by zadziałało find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
— Juan Calero,

9

Sądząc po sekcji „OBEJMUJ / WYŁĄCZ ZASADY WZORU” na stronie podręcznika , sposobem na to jest

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

Krytyczną różnicą między tym a odpowiedzią kbrd jest --include="*/"flaga, która mówi rsync, aby poszła naprzód i skopiowała znalezione katalogi, bez względu na ich nazwę. Jest to konieczne, ponieważ rsync nie będzie się powtarzał w podkatalogu, chyba że otrzyma polecenie skopiowania tego podkatalogu.

Zauważ też, że znaki cudzysłowu uniemożliwiają powłoce próbowanie rozwinięcia wzorców do nazw plików względem bieżącego katalogu i wykonanie jednej z następujących czynności:

  1. Sukces i zepsucie filtra (niezbyt prawdopodobne w środku takiej flagi, chociaż tak naprawdę nigdy nie wiadomo, kiedy ktoś utworzy plik o nazwie --include=foo.pdf...)

  2. Niepowodzenie i potencjalnie generowanie błędu zamiast uruchamiania polecenia (tak jak odkryłeś, że domyślnie robi to zsh).


Skopiuje to tylko pliki PDF i strukturę katalogów, a kbrd skopiuje pliki, ale zignoruje strukturę?
— Seamus

1
Hmm Wydaje mi się, że to wciąż próbuje skopiować wszystko, ponieważ robi to bez filtra, więc includedodatkowe rzeczy już tam nic nie zmieniają. Jeśli rozumiesz, co mam na myśli ...
— Seamus

7
Potrzebujesz --exclude="*"po --include="*.pdf", albo to wszystko przeniesie.
— jmanning2k

@ jmanning2k: Ah. Dobrze wiedzieć!
— SamB

4

Co powiesz na to:

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

Nie, man rsyncumieszcza filtr po opcjach i przed źródłem / przeznaczeniem. Próbowałem tego i nie zadziałało
— Seamus

Twoja droga znajduje pliki .pdf w bieżącym folderze, ale nie rekurencyjnie, jak chcę. ( aopcja dotyczy archiwizacji i powoduje, że kopiowanie jest rekurencyjne.
— Seamus

1
Ups, mój zły. Zaktualizowałem swoją odpowiedź.
— kbyrd

+1 za bycie tak blisko i wskazanie mi, jak znaleźć odpowiedni materiał na stronie podręcznika. (Mam nadzieję, że nawet dobrze to
— zrozumiałem

3

Oto coś, co powinno działać bez użycia find. Różnica w stosunku do już opublikowanych odpowiedzi polega na kolejności reguł filtrowania. Reguły filtrowania w komendzie rsync działają podobnie jak reguły iptable, pierwsza reguła, do której pasuje plik, jest tą, która jest używana. Ze strony podręcznika :

Gdy tworzona jest lista plików / katalogów do przesłania, rsync sprawdza kolejno każdą nazwę, która ma zostać przesłana, z listą wzorców włączania / wykluczania, a następnie uruchamiany jest pierwszy pasujący wzorzec: jeśli jest to wzorzec wykluczenia, to ten plik jest pominięty; jeśli jest to wzorzec dołączania, nazwa pliku nie jest pomijana; jeśli nie znaleziono pasującego wzorca, nazwa pliku nie jest pomijana.

Dlatego potrzebujesz następującego polecenia:

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

Zwróć uwagę na wzorzec „**. Pdf”. Według strony podręcznika :

jeśli wzorzec zawiera / (nie licząc końcowego /) lub „**”, to jest dopasowywany do pełnej nazwy ścieżki, w tym do wiodących katalogów. Jeśli wzorzec nie zawiera znaku / lub „**”, to jest dopasowywany tylko do końcowego komponentu nazwy pliku. (Pamiętaj, że algorytm jest stosowany rekurencyjnie, więc „pełna nazwa pliku” może faktycznie być dowolną częścią ścieżki od katalogu początkowego w dół

W moim małym teście działa to rekurencyjnie w dół drzewa katalogów i wybiera tylko pliki pdf.


Jak dokładnie testowałeś? Zgodnie z moim rozumieniem dokumentacji i weryfikacją eksperymentalną twoje polecenie powinno być kopiowane tylko *.pdfw katalogu najwyższego poziomu (ale nie ~/LaTeX/foo/bar.pdf).
— Gilles

@Gilles Crud. Masz rację. Przysięgałem, że to przetestowałem i zadziałało, ale nie mogę tego odtworzyć. A teraz, kiedy faktycznie przeczytałem stronę podręcznika, którą zacytowałem, ma sens, że to nie działa. Narzekać.
— Steven D

1
Cóż, zrozumiałem, gdzie mój test był zły. Mój „mały test” był w katalogu, który zawiera własne pliki .tex i .pdf. Następnie utworzyłem podkatalog „test” oraz test.pdf i test.tex w tym podkatalogu. Jednak nie zauważyłem, że w moim katalogu najwyższego poziomu znajdował się plik test.pdf, prawdopodobnie z powodu jakiegoś szybkiego eksperymentu LaTeX, który zrobiłem.
— Steven D

Nadal nie rozumiem **. Byłoby miło mieć tego przykład. ;)
— buhtz

2

To jest moje preferowane rozwiązanie:

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

findPolecenia jest łatwiejsza do zrozumienia niż włączania / wyłączania reguł rsync:-)

Jeśli chcesz skopiować tylko pliki pdf, po prostu zmień .jpgna.pdf

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.