Filtre Rsync: copier un seul motif

128

J'essaie de créer un répertoire qui contiendra tous et uniquement mes PDF compilés à partir de LaTeX. J'aime garder chaque projet dans un dossier séparé, le tout logé dans un grand dossier appelé LaTeX. Alors j'ai essayé de courir:

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

qui devrait trouver tous les fichiers PDF ~/LaTeX/et les transférer dans le dossier de sortie. Ça ne marche pas. Il me dit qu'il n'a trouvé aucune correspondance pour " *.pdf". Si je laisse ce filtre de côté, la commande répertorie tous les fichiers de tous les dossiers du projet sous LaTeX. C'est donc un problème avec le filtre * .pdf. J'ai essayé de remplacer ~/par le chemin complet de mon répertoire personnel, mais cela n'a pas eu d'effet.

Je suis en utilisant zsh. J'ai essayé de faire la même chose en bash et même avec le filtre qui répertorie chaque fichier dans chaque sous-répertoire ... Qu'est-ce qui se passe ici?

Pourquoi rsync ne comprend-il pas mon filtre PDF uniquement?


D'ACCORD. Donc mise à jour: Non j'essaie

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

Et cela me donne la liste complète des fichiers. Je suppose que tout correspond au premier motif ...

Seamus
la source
euh, vous semblez avoir raison ... Je pense que ma réponse (en utilisant le **motif de zsh ) devrait marcher, cependant.
Marcel Stimberg le

Réponses:

248

TL, DR:

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

Rsync copie la ou les sources vers la destination. Si vous passez en *.pdftant que sources, le shell étend cette liste à la liste des fichiers portant l' .pdfextension dans le répertoire en cours. Aucune traversée récursive ne se produit car vous n'avez passé aucun répertoire en tant que source.

Vous devez donc exécuter rsync -a ~/LaTeX/ ~/Output/, mais avec un filtre, indiquer à rsync de ne copier .pdfque les fichiers. Les règles de filtrage de Rsync peuvent sembler décourageantes lorsque vous lisez le manuel, mais vous pouvez construire de nombreux exemples avec quelques règles simples.

  • Inclusions et exclusions:

    • Exclusion de fichiers par nom ou par emplacement est facile: --exclude=*~, --exclude=/some/relative/location( par rapport à l'argument source, par exemple ceci exclut ~/LaTeX/some/relative/location).
    • Si vous souhaitez uniquement faire correspondre quelques fichiers ou emplacements, incluez-les, incluez tous les répertoires qui y mènent (par exemple avec --include=*/), puis excluez le reste avec --exclude='*'. Ceci est dû au fait:
    • Si vous excluez un répertoire, cela exclut tout ce qui se trouve en dessous. Les fichiers exclus ne seront pas pris en compte du tout.
    • Si vous incluez un répertoire, cela n'inclut pas automatiquement son contenu. Dans les versions récentes, --include='directory/***'nous le ferons.
    • Pour chaque fichier, la première règle de correspondance s'applique (et tout ce qui ne correspond jamais est inclus).
  • Les motifs:

    • Si un modèle ne contient pas de /, il s'applique au nom de fichier sans répertoire.
    • Si un modèle se termine par /, il s’applique uniquement aux répertoires.
    • Si un modèle commence par /, il s'applique à tout le chemin du répertoire passé en argument rsync.
    • *toute sous-chaîne d'un seul composant de répertoire (c'est-à-dire qu'elle ne correspond jamais /); **correspond à n'importe quelle sous-chaîne de chemin.
  • Si un argument source se termine par un /, son contenu est copié ( rsync -r a/ bcrée b/foopour chaque a/foo). Sinon, le répertoire lui-même est copié ( rsync -r a bcrée b/a).


Nous devons donc inclure *.pdf, inclure les répertoires les contenant et exclure tout le reste.

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

Notez que cela copie tous les répertoires, même ceux qui ne contiennent aucun fichier ou sous-répertoire correspondant. Cela peut être évité avec l' --prune-empty-dirsoption (ce n'est pas une solution universelle car vous ne pouvez pas copier un répertoire même en le faisant correspondre explicitement, mais c'est une exigence rare).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
Gilles
la source
Contrairement à ma solution (utilisant le **modèle de zsh ), cela recrée la structure de répertoires dans le répertoire cible. Je ne sais pas si c'est ce que le PO veut ...
Marcel Stimberg le
Je veux inclure un seul répertoire et exclure le reste de tous les répertoires du /etc/lsyncd/lsyncd.conf.luafichier. Avez-vous une idée?
Dhaduk Mitesh
@DhadukMitesh Je ne connais pas lsyncd. Vous devriez poser cette question comme une nouvelle question.
Gilles
25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

La valeur par défaut consiste à tout inclure. Vous devez donc explicitement tout exclure après avoir inclus les fichiers que vous souhaitez transférer. Supprimez le --dry-run pour transférer les fichiers.

Si vous commencez avec:

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

Ensuite, la correspondance gourmande exclura tout de suite.

Si tu essayes:

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

Ensuite, seuls les fichiers pdf du dossier de niveau supérieur seront transférés. Il ne suivra aucun répertoire, car ceux-ci sont exclus par '*'.

jmanning2k
la source
2
Depuis le 2014-03-17, c’est la meilleure réponse, car elle résout exactement la question des affiches originales . S'il vous plaît votez-le! Si vous ajoutez --prune-empty-dirs(ou raccourci -m), vous vous épargnez même de nombreux répertoires vides sur la destination, sauf bien sûr, vous les souhaitez comme rappel ou modèle de structure.
porg
1
Meilleure réponse, --include = "* /" est la clé.
Martin Konicek
Je veux inclure un seul répertoire et exclure le reste de tous les répertoires du /etc/lsyncd/lsyncd.conf.luafichier. Avez-vous une idée?
Dhaduk Mitesh
15

Si vous utilisez un modèle tel que *.pdf, le shell "développe" ce modèle, c'est-à-dire qu'il remplace le modèle par toutes les correspondances du répertoire en cours. La commande que vous exécutez (dans ce cas, rsync) ignore que vous avez essayé d'utiliser un modèle.

Lorsque vous utilisez zsh , il existe une solution simple: Le **modèle peut être utilisé pour faire correspondre les dossiers de manière récursive. Essaye ça:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
Marcel Stimberg
la source
Est-ce que cela ne copierait pas tous les fichiers .pdf quelque part dans le répertoire courant et tout de ~ / LaTeX / à ~ / Output?
SamB
Je suppose que vous vouliez dire rsync -avn ~/LaTeX/**/*.pdf ~/Output, mais la solution avec --includeest plus évolutive de toute façon.
Adam Byrtek le
Désolé, j'ai corrigé la commande que j'ai mal saisie à la hâte ... Je conviens que la commande include (dans la version de SamB) est meilleure, bien qu'elle soit un peu plus compliquée et spécifique à rsync, alors qu'elle **pourrait également s'avérer utile dans d'autres situations.
Marcel Stimberg
1
Bash 4 a adopté la même fonctionnalité. Oh, et vous n'avez pas besoin de rsync ici, cp fera l'affaire. Sur certains systèmes, s’il ya beaucoup de fichiers, il est préférable cd ~/Latex && cp -p **/*.pdf ~/Outputd’éviter une erreur «ligne de commande trop longue».
Gilles
1
Notez que les modèles de rsync utilisés dans les filtres d'inclusion et d'exclusion ont également un ** qui fait la même chose. Vous pouvez échapper aux * coquilles d'autres coquilles en les mettant entre guillemets.
Dan Pritts
13

Vous pouvez utiliser findune liste intermédiaire de fichiers ( files_to_copy) pour résoudre votre problème. Assurez-vous que vous êtes dans votre répertoire personnel, puis:

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

Testé avec Bash.

Derek Frye
la source
Je pense que cette recherche est la solution la plus robuste, mais j’opterais pour l’ -execoption trouvailles ou l’utilisation de xargs. Quelque chose comme:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D
Ouais ... Je suggérerais de trouver aussi bien que j'imagine que rsync doit être capable de faire ça.
Gabe.
C’est aussi une solution intéressante à un problème plus complexe: je pourrais probablement l’utiliser pour exclure les fichiers dont la classe de document est standaloneou qui n’ont pas de .texfichier du même nom, car ce sont des images incluses dans certains documents ...
Seamus
2
L'option rsync --files-fromaccepte la lecture de stdin. Cela fonctionnerait find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero
9

A en juger par la section "INCLUDE / EXCLUDE PATTERN RULES" de la page de manuel , la manière de procéder est la suivante:

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

La différence critique entre ceci et la réponse de kbrd est le --include="*/"drapeau, qui indique à rsync de continuer et de copier tous les répertoires trouvés, quel que soit leur nom. Cela est nécessaire car rsync ne recurse pas dans un sous-répertoire à moins d’avoir été invité à copier ce sous-répertoire.

Notez également que les guillemets empêchent le shell d'essayer de développer les modèles en noms de fichiers relatifs au répertoire en cours et d'effectuer l'une des opérations suivantes:

  1. Réussir et gâcher votre filtre (pas très probablement au milieu d'un drapeau comme celui-ci, bien que vous ne sachiez jamais quand quelqu'un créera un fichier nommé --include=foo.pdf...)

  2. Échec et éventuellement production d’une erreur au lieu d’exécuter la commande (comme vous avez découvert zsh le fait par défaut).

SamB
la source
Donc, cela ne copiera que les PDF et la structure de répertoires, tandis que celui de kbrd copiera les fichiers, mais ignorera la structure?
Seamus
1
Hmm. En fait, cela semble toujours essayer de tout copier, je suppose parce que c'est ce qui est fait sans le filtre, donc includeajouter des éléments supplémentaires ne change rien. Si vous voyez ce que je veux dire ...
Seamus
7
Vous avez besoin --exclude="*"après le --include="*.pdf", ou cela transférera tout.
jmanning2k
@ Jmanning2k: Ah. Bon à savoir!
SamB
4

Que dis-tu de ça:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
kbyrd
la source
Non, man rsyncplace le filtre après les options et avant la source / destination. J'ai essayé cela et cela n'a pas fonctionné
Seamus
Votre chemin trouve les fichiers .pdf dans le dossier actuel, mais pas récursivement, comme je le veux. (l' aoption est pour l'archive et entre autres choses, elle rend la copie récursive.
Seamus
1
Ooops, mon mauvais. J'ai mis à jour ma réponse.
kbyrd
+1 pour être si proche et me donner un indice sur la façon de trouver le matériel pertinent dans la page de manuel. (J'espère même que j'ai bien compris. :-)
SamB
3

Voici quelque chose qui devrait fonctionner sans utiliser find. La différence par rapport aux réponses déjà postées correspond à l'ordre des règles de filtrage. Les règles de filtrage dans une commande rsync fonctionnent beaucoup comme les règles iptables, la première règle à laquelle un fichier correspond est celle utilisée. De la page de manuel :

Au fur et à mesure que la liste des fichiers / répertoires à transférer est construite, rsync vérifie tour à tour chaque nom à transférer avec la liste des modèles d'inclusion / exclusion, et le premier modèle correspondant est traité: s'il s'agit d'un modèle d'exclusion, alors ce fichier est sauté; s'il s'agit d'un modèle d'inclusion, le nom de fichier n'est pas ignoré; si aucun motif correspondant n'est trouvé, le nom du fichier n'est pas ignoré.

Ainsi, vous avez besoin d'une commande comme suit:

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

Notez le motif "**. Pdf". Selon la page de manuel :

si le modèle contient un / (sans compter un /) ou un "**", il est comparé au nom de chemin complet, y compris tous les principaux répertoires. Si le modèle ne contient pas de / ou "**", il ne correspond alors qu'au dernier composant du nom du fichier. (Rappelez-vous que l'algorithme est appliqué de manière récursive afin que "nom de fichier complet" puisse en réalité être n'importe quelle partie d'un chemin du répertoire de départ

Dans mon petit test, cela fonctionne de manière récursive dans l'arborescence de répertoires et ne sélectionne que les fichiers PDF.

Steven D
la source
Comment avez-vous testé exactement? Selon ma compréhension de la documentation et ma vérification expérimentale, votre commande ne doit être *.pdfcopiée que dans le répertoire toplevel (mais pas ~/LaTeX/foo/bar.pdf).
Gilles
@ Gilles Crud. Tu as raison. J'ai juré avoir testé cela et cela a fonctionné, mais je n'arrive pas à le recréer. Et maintenant que j'ai lu la page de manuel que j'ai citée, il est logique que cela ne fonctionne pas. Plaindre.
Steven D
1
Eh bien, j'ai compris où mon test était faux. Mon "petit test" portait sur un répertoire contenant les fichiers .tex et .pdf. J'ai ensuite créé un sous-répertoire "test" et un test.pdf et test.tex dans ce sous-répertoire. Cependant, je n'ai pas remarqué qu'il y avait un test.pdf dans mon répertoire de premier niveau, probablement à cause d'une expérience rapide de l'expérience LaTeX que j'ai faite.
Steven D
Je ne comprends toujours pas le **. Ce serait bien d'en avoir un exemple. ;)
buhtz
2

Ceci est ma solution préférée:

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

La findcommande est plus facile à comprendre que les règles d'inclusion / exclusion de rsync:-)

Si vous souhaitez copier uniquement des fichiers pdf, il suffit de changer .jpgà.pdf

Guettli
la source