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.