Rsync-Filter: Kopieren nur eines Musters

128

Ich versuche, ein Verzeichnis zu erstellen, in dem alle und nur meine aus LaTeX kompilierten PDF-Dateien gespeichert werden. Ich mag es, jedes Projekt in einem separaten Ordner zu speichern, der sich alle in einem großen Ordner namens befindet LaTeX. Also habe ich versucht zu rennen:

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

das sollte alle pdfs in finden ~/LaTeX/und sie in den ausgabeordner übertragen. Das geht nicht. Es wird mir mitgeteilt, dass für " *.pdf" keine Übereinstimmungen gefunden wurden . Wenn ich diesen Filter auslasse, listet der Befehl alle Dateien in allen Projektordnern unter LaTeX auf. Es ist also ein Problem mit dem * .pdf-Filter. Ich habe versucht, ~/durch den vollständigen Pfad zu meinem Ausgangsverzeichnis zu ersetzen , aber das hatte keine Auswirkungen.

Ich benutze zsh. Ich habe versucht, dasselbe in bash und sogar mit dem Filter zu tun, der jede einzelne Datei in jedem Unterverzeichnis auflistet ... Was ist hier los?

Warum versteht rsync meinen PDF-Filter nicht?


OKAY. Also Update: Nein, ich versuche es

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

Und das gibt mir die ganze Dateiliste. Ich denke, weil alles zum ersten Muster passt ...

Seamus
quelle
ähm, du scheinst recht zu haben ... Ich denke, meine Antwort (unter Verwendung von zshs **Muster) sollte funktionieren.
Marcel Stimberg

Antworten:

248

TL, DR:

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

Rsync kopiert die Quelle (n) zum Ziel. Wenn Sie *.pdfals Quellen übergeben, erweitert die Shell dies auf die Liste der Dateien mit der .pdfErweiterung im aktuellen Verzeichnis. Es findet keine rekursive Durchquerung statt, da Sie kein Verzeichnis als Quelle übergeben haben.

Sie müssen also ausführen rsync -a ~/LaTeX/ ~/Output/, aber mit einem Filter, um rsync anzuweisen, .pdfnur Dateien zu kopieren . Die Filterregeln von Rsync können beim Lesen des Handbuchs entmutigend wirken, Sie können jedoch mit nur wenigen einfachen Regeln viele Beispiele erstellen.

  • Ein- und Ausschlüsse:

    • Ausschließen von Dateien nach Name oder Ort ist einfach: --exclude=*~, --exclude=/some/relative/location(bezogen auf das Quellargument, zB Ausgeschlossen sind ~/LaTeX/some/relative/location).
    • Wenn Sie nur einige Dateien oder Speicherorte abgleichen möchten, schließen Sie sie ein, schließen Sie jedes Verzeichnis ein, das zu ihnen führt (zum Beispiel mit --include=*/), und schließen Sie den Rest mit aus --exclude='*'. Das ist weil:
    • Wenn Sie ein Verzeichnis ausschließen, wird alles darunter ausgeschlossen. Die ausgeschlossenen Dateien werden überhaupt nicht berücksichtigt.
    • Wenn Sie ein Verzeichnis einfügen, wird der Inhalt nicht automatisch eingefügt. In neueren Versionen --include='directory/***'wird das erledigt.
    • Für jede Datei gilt die erste Übereinstimmungsregel (und alles, was niemals übereinstimmt, ist enthalten).
  • Muster:

    • Wenn ein Muster kein a enthält /, gilt es für den Dateinamen sans directory.
    • Wenn ein Muster mit endet /, gilt es nur für Verzeichnisse.
    • Wenn ein Muster mit beginnt /, gilt es für den gesamten Pfad aus dem Verzeichnis, an das als Argument übergeben wurde rsync.
    • *ein beliebiger Teilstring einer einzelnen Verzeichniskomponente (dh er stimmt nie überein /); **Stimmt mit jedem Pfad-Teilstring überein.
  • Wenn eine Quelle Argument mit einem Ende /, dessen Inhalt kopiert werden ( rsync -r a/ berstellt b/foofür jeden a/foo). Andernfalls wird das Verzeichnis selbst kopiert ( rsync -r a berstellt b/a).


Daher müssen wir hier *.pdfVerzeichnisse einschließen , die sie enthalten, und alles andere ausschließen.

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

Beachten Sie, dass hierdurch alle Verzeichnisse kopiert werden, auch diejenigen, die keine übereinstimmende Datei oder kein entsprechendes Unterverzeichnis enthalten. Dies kann mit der --prune-empty-dirsOption vermieden werden (dies ist keine universelle Lösung, da Sie dann ein Verzeichnis nicht einmal kopieren können, indem Sie es explizit abgleichen, dies ist jedoch eine seltene Anforderung).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
Gilles
quelle
Im Gegensatz zu meiner Lösung (mit dem **Muster von zsh ) wird hierdurch die Verzeichnisstruktur im Zielverzeichnis neu erstellt. Ich bin nicht sicher, ob dies das ist, was die OP will ...
Marcel Stimberg
Ich möchte nur ein Verzeichnis einschließen und den Rest des gesamten Verzeichnisses in der /etc/lsyncd/lsyncd.conf.luaDatei ausschließen. Hast du eine Idee?
Dhaduk Mitesh
@ DhadukMitesh Ich bin nicht vertraut mit lsyncd. Sie sollten dies als neue Frage stellen.
Gilles
25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

In der Standardeinstellung wird alles eingeschlossen, sodass Sie nach dem Einschließen der zu übertragenden Dateien explizit alles ausschließen müssen . Entfernen Sie den --dry-run, um die Dateien tatsächlich zu übertragen.

Wenn Sie anfangen mit:

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

Dann schließt das gierige Matching alles gleich aus.

Wenn du es versuchst:

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

Dann werden nur PDF-Dateien in den Ordner der obersten Ebene übertragen. Es folgen keine Verzeichnisse, da diese durch '*' ausgeschlossen sind.

jmanning2k
quelle
2
Ab dem 17.03.2014 ist dies die beste Antwort, da sie die Frage nach dem Original-Poster genau löst . Bitte stimmen Sie ab! Wenn Sie eine --prune-empty-dirsVerknüpfung hinzufügen, sparen -mSie sich sogar viele leere Verzeichnisse am Zielort, außer Sie möchten sie natürlich als Erinnerung oder strukturelle Blaupause.
Porg
1
Beste Antwort: --include = "* /" ist der Schlüssel.
Martin Konicek
Ich möchte nur ein Verzeichnis einschließen und den Rest des gesamten Verzeichnisses in der /etc/lsyncd/lsyncd.conf.luaDatei ausschließen. Hast du eine Idee?
Dhaduk Mitesh
15

Wenn Sie ein Muster wie dieses verwenden *.pdf, „erweitert“ die Shell dieses Muster, dh sie ersetzt das Muster durch alle Übereinstimmungen im aktuellen Verzeichnis. Dem ausgeführten Befehl (in diesem Fall rsync) ist nicht bekannt, dass Sie versucht haben, ein Muster zu verwenden.

Wenn Sie zsh verwenden , gibt es jedoch eine einfache Lösung: Das **Muster kann verwendet werden, um Ordner rekursiv abzugleichen. Versuche dies:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
Marcel Stimberg
quelle
Würde das nicht alle pdfs von irgendwo im aktuellen Verzeichnis und alles von ~ / LaTeX / nach ~ / Output kopieren ?
SamB
Ich denke du meintest rsync -avn ~/LaTeX/**/*.pdf ~/Output, aber die Lösung mit --includeist trotzdem skalierbarer.
Adam Byrtek
Entschuldigung, den Befehl, den ich in Eile falsch eingegeben habe, korrigiert. Ich stimme zu, dass der Befehl include (in der SamB-Version) besser ist, obwohl er etwas komplizierter und spezifischer für rsync ist, während der Befehl **in anderen Situationen nützlich sein könnte.
Marcel Stimberg
1
Bash 4 hat das gleiche Feature übernommen. Oh, und Sie brauchen hier kein rsync, cp wird es tun. Auf einigen Systemen ist es hilfreich, wenn viele Dateien vorhanden sind cd ~/Latex && cp -p **/*.pdf ~/Output, um einen Fehler zu vermeiden, dass die Befehlszeile zu lang ist.
Gilles
1
Beachten Sie, dass die in den Einschluss- und Ausschlussfiltern verwendeten rsync-Muster auch ein ** aufweisen, das dasselbe bewirkt. Sie können * 's aus anderen Shells entfernen, indem Sie sie in Anführungszeichen setzen.
Dan Pritts
13

Sie können findeine Zwischenliste von Dateien ( files_to_copy) verwenden, um Ihr Problem zu lösen. Stellen Sie sicher, dass Sie sich in Ihrem Home-Verzeichnis befinden.

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

Mit Bash getestet.

Derek Frye
quelle
Ich denke, dass find die robusteste Lösung ist, aber ich würde mich dafür entscheiden, entweder finds -execoption oder using zu verwenden xargs. So etwas wie:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D
Ja ... Ich würde vorschlagen , auch finden ... obwohl ich rsync vorstellen muß der Lage sein , dies zu tun.
gabe.
Dies ist auch eine gute Lösung für ein schwierigeres Problem: Vermutlich könnte ich damit Dateien ausschließen, deren Dokumentenklasse standaloneeine .texDatei mit demselben Namen ist oder nicht , da dies Bilder sind, die in einem Dokument enthalten sind ...
Seamus
2
Die Option rsync --files-fromakzeptiert das Lesen von stdin. Dies würde funktionieren find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero
9

Nach dem Abschnitt "INCLUDE / EXCLUDE PATTERN RULES" auf der Manpage zu urteilen, ist dies der richtige Weg

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

Der entscheidende Unterschied zwischen dieser und der Antwort von kbrd ist das --include="*/"Flag, das rsync anweist, alle gefundenen Verzeichnisse zu kopieren, unabhängig von ihrem Namen. Dies ist erforderlich, da rsync nicht in ein Unterverzeichnis zurückkehrt, es sei denn, es wurde angewiesen, dieses Unterverzeichnis zu kopieren.

Beachten Sie auch, dass die Anführungszeichen verhindern, dass die Shell versucht, die Muster zu Dateinamen relativ zum aktuellen Verzeichnis zu erweitern, und eine der folgenden Aktionen ausführt:

  1. Erfolgreicher und durcheinander bringender Filter (nicht allzu wahrscheinlich in der Mitte einer solchen Flagge, obwohl Sie wirklich nie wissen, wann jemand eine Datei mit dem Namen --include=foo.pdf... erstellt)

  2. Wenn dies fehlschlägt und möglicherweise ein Fehler auftritt, anstatt den Befehl auszuführen (wie Sie es bei zsh standardmäßig festgestellt haben).

SamB
quelle
Das kopiert also nur die PDFs und die Verzeichnisstruktur, während kbrd die Dateien kopiert, aber die Struktur ignoriert?
Seamus
1
Hmm. Dies scheint immer noch alles zu versuchen und zu kopieren, ich schätze, weil es das ist, was es ohne den Filter macht, also includeändert es nichts , wenn zusätzliches Zeug bereits darin ist. Wenn Sie sehen, was ich meine ...
Seamus
7
Du brauchst --exclude="*"nach dem --include="*.pdf", sonst wird alles übertragen.
Jmanning2k
@ jmanning2k: Ah. Gut zu wissen!
SamB
4

Wie wäre es damit:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
kbyrd
quelle
Nein, man rsyncsetzt den Filter hinter die Optionen und vor die Quelle / Ziele. Ich habe es versucht und es hat nicht funktioniert
Seamus
Ihr Weg findet .pdf-Dateien im aktuellen Ordner, aber nicht rekursiv, wie ich will. (Die aOption ist für die Archivierung und unter anderem macht es das Kopieren rekursiv.
Seamus
1
Hoppla, mein Schlimmes. Ich habe meine Antwort aktualisiert.
kbyrd
+1 für die Nähe und einen Hinweis darauf, wie ich das relevante Material auf der Handbuchseite finden kann. (Hoffentlich habe ich es sogar richtig gemacht. :-)
SamB
3

Hier ist etwas, das funktionieren sollte, ohne find zu verwenden. Der Unterschied zu bereits geposteten Antworten ist die Reihenfolge der Filterregeln. Filterregeln in einem rsync-Befehl funktionieren ähnlich wie iptable-Regeln. Die erste Regel, mit der eine Datei übereinstimmt, wird verwendet. Von der Manualseite :

Während die Liste der zu übertragenden Dateien / Verzeichnisse erstellt wird, vergleicht rsync die zu übertragenden Namen der Reihe nach mit der Liste der Einschluss- / Ausschlussmuster, und das erste übereinstimmende Muster wird berücksichtigt: Wenn es sich um ein Ausschlussmuster handelt, handelt es sich um diese Datei übersprungen; Wenn es sich um ein Include-Muster handelt, wird dieser Dateiname nicht übersprungen. Wird kein passendes Muster gefunden, wird der Dateiname nicht übersprungen.

Daher benötigen Sie einen Befehl wie folgt:

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

Beachten Sie das Muster "**. Pdf". Nach der Manpage :

Wenn das Muster ein / (ohne abschließendes /) oder ein "**" enthält, wird es mit dem vollständigen Pfadnamen abgeglichen, einschließlich aller führenden Verzeichnisse. Wenn das Muster kein / oder "**" enthält, wird es nur mit der letzten Komponente des Dateinamens abgeglichen. (Denken Sie daran, dass der Algorithmus rekursiv angewendet wird, sodass "vollständiger Dateiname" tatsächlich ein beliebiger Teil eines Pfades vom Startverzeichnis abwärts sein kann

In meinem kleinen Test funktioniert dies rekursiv im Verzeichnisbaum und wählt nur die PDFs aus.

Steven D
quelle
Wie genau hast du getestet? Nach meinem Verständnis der Dokumentation und meiner experimentellen Überprüfung sollte Ihr Befehl nur *.pdfin das oberste Verzeichnis kopiert werden (aber nicht ~/LaTeX/foo/bar.pdf).
Gilles
@ Gilles Crud. Du hast recht. Ich habe geschworen, dass ich das getestet habe und es funktioniert hat, aber ich kann es scheinbar nicht nachvollziehen. Und jetzt, da ich die von mir zitierte Manpage tatsächlich gelesen habe, macht es Sinn, dass es nicht funktioniert. Murren.
Steven D
1
Nun, ich habe herausgefunden, wo mein Test falsch war. Mein "kleiner Test" befand sich in einem Verzeichnis mit eigenen .tex- und .pdf-Dateien. Ich habe dann ein "test" -Unterverzeichnis und ein test.pdf und test.tex in diesem Unterverzeichnis erstellt. Es ist mir jedoch nicht aufgefallen, dass sich in meinem Verzeichnis auf oberster Ebene eine test.pdf befand, wahrscheinlich aufgrund eines kurzen LaTeX-Experiments, das ich durchgeführt habe.
Steven D
Ich verstehe das immer noch nicht **. Wäre schön ein Beispiel dafür zu haben. ;)
Buhtz
2

Dies ist meine bevorzugte Lösung:

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

Der findBefehl ist einfacher zu verstehen als die Einschluss- / Ausschlussregeln von rsync:-)

Wenn Sie nur PDF-Dateien kopieren möchten, wechseln Sie einfach .jpgzu.pdf

guettli
quelle