web-dev-qa-db-fra.com

Filtre Rsync: copie d'un seul motif

J'essaie de créer un répertoire qui hébergera tous et seulement mes PDF compilés à partir de LaTeX. J'aime garder chaque projet dans un dossier séparé, tous hébergés dans un grand dossier appelé LaTeX. J'ai donc essayé de courir:

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

qui devrait trouver tous les fichiers PDF dans ~/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 de côté ce filtre, la commande répertorie tous les fichiers dans tous les dossiers de projet sous LaTeX. C'est donc un problème avec le filtre * .pdf. J'ai essayé de remplacer ~/ avec le chemin complet de mon répertoire personnel, mais cela n'a pas eu d'effet.

J'utilise 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 ... Que se passe-t-il ici?

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


D'ACCORD. Alors mise à jour: non j'essaye

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 ...

142
Seamus

TL, DR:

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

Rsync copie la ou les sources vers la destination. Si vous réussissez *.pdf en tant que sources, le shell étend cela à la liste des fichiers avec le .pdf extension dans le répertoire courant. Aucune traversée récursive ne se produit car vous n'avez transmis aucun répertoire en tant que source.

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

  • Inclusions et exclusions:

    • Il est facile d'exclure des fichiers par nom ou par emplacement: --exclude=*~, --exclude=/some/relative/location (par rapport à l'argument source, par exemple, cela exclut ~/LaTeX/some/relative/location).
    • Si vous ne souhaitez faire correspondre que 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 du tout pris en compte.
    • Si vous incluez un répertoire, cela n'inclut pas automatiquement son contenu. Dans les versions récentes, --include='directory/***' Fera cela.
    • Pour chaque fichier, la première règle de correspondance s'applique (et tout ce qui ne correspond jamais est inclus).
  • Motifs:

    • Si un modèle ne contient pas de /, il s'applique au nom de fichier sans répertoire.
    • Si un motif se termine par /, il s'applique uniquement aux répertoires.
    • Si un modèle commence par /, il s'applique à l'ensemble du chemin du répertoire passé en argument à rsync.
    • * toute sous-chaîne d'un composant de répertoire unique (c'est-à-dire 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/ b crée b/foo pour chaque a/foo). Sinon, le répertoire lui-même est copié (rsync -r a b crée b/a).


Ainsi, ici, nous devons 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 en contenant un. Cela peut être évité avec le --Prune-empty-dirs option (ce n'est pas une solution universelle puisque vous ne pouvez alors 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/
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

La valeur par défaut est de tout inclure, vous devez donc explicitement tout exclure après y compris les fichiers que vous souhaitez transférer. Supprimez le --dry-run pour transférer réellement les fichiers.

Si vous commencez avec:

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

Ensuite, l'appariement gourmand exclura tout de suite.

Si tu essayes:

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

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 '*'.

30
jmanning2k

Si vous utilisez un modèle comme *.pdf, le Shell "étend" ce modèle, c'est-à-dire qu'il remplace le modèle par toutes les correspondances dans le répertoire courant. 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 cependant une solution simple: le ** le modèle peut être utilisé pour faire correspondre les dossiers de manière récursive. Essaye ça:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
15
Marcel Stimberg

Vous pouvez utiliser find et une 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.

13
Derek Frye

A en juger par la section "INCLURE/EXCLUDE PATTERN RULES" de la manpage , la façon de procéder est

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

La différence critique entre cela et la réponse de kbrd est le --include="*/" flag, qui indique à rsync d'aller de l'avant et de copier tous les répertoires qu'il trouve, quels qu'ils soient. Ceci est nécessaire car rsync ne récursera pas dans un sous-répertoire à moins qu'il n'ait été invité à copier ce sous-répertoire.

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

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

  2. Échec, et produisant potentiellement une erreur au lieu d'exécuter la commande (comme vous l'avez découvert par défaut avec zsh).

9
SamB

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

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

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

Si vous souhaitez copier uniquement des fichiers pdf, modifiez simplement .jpg à .pdf

3
guettli

Que dis-tu de ça:

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

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

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

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

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

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

si le modèle contient un/(sans compter un// de fin) ou un "**", il est comparé au nom de chemin complet, y compris les répertoires de tête. Si le modèle ne contient pas de/ou de "**", il est mis en correspondance uniquement avec le dernier composant du nom de fichier. (N'oubliez pas que l'algorithme est appliqué de manière récursive afin que "nom de fichier complet" puisse en fait être n'importe quelle partie d'un chemin à partir du répertoire de départ vers le bas

Dans mon petit test, cela fonctionne récursivement dans l'arborescence des répertoires et ne sélectionne que les fichiers PDF.

2
Steven D

Pour générer un répertoire contenant uniquement des en-têtes (../include) depuis l'intérieur du répertoire source:

rsync -avh --Prune-empty-dirs --exclude="build" --include="*/" --include="*.h" --exclude="*" ./* ../include/

Cela exclut tous les répertoires vides et le répertoire build

0
SCG82