rsync une liste de répertoires avec chemin absolu dans un fichier texte

9

J'ai un fichier texte contenant une liste de répertoires avec son chemin absolu

$ cat DirectoriesToCopy.txt

/data/Dir1
/data/Dir2

Je veux utiliser rsync pour copier tous ces répertoires en préservant son chemin absolu vers un autre emplacement.

J'ai essayé la commande rsync suivante, mais cela ne fonctionne pas

rsync -avr --include-from=DirectoriesToCopy.txt --exclude='*/' --exclude='/*'  /  /media/MyDestination/

Qu'est-ce qui ne va pas ici?

indiajoe
la source
Voulez-vous transférer /data/Dir1et /data/Dir2inclure leur contenu vers /media/MyDestination/Dir1et /media/MyDestination/Dir2? Ou voulez-vous inclure la /datapièce? Quelle est la taille de cette liste, est-elle trop grande pour simplement lister ces entrées sur la ligne de commande? Quoi qu'il en soit, vos --excludedéclarations empêchent la récursivité.
wurtel
Je souhaite également transférer tous les fichiers à l'intérieur de ces répertoires. Il y a beaucoup de fichiers dans ce répertoire, donc je voudrais éviter de créer un autre fichier texte avec tous les noms de fichiers.
indiajoe
Je voudrais garder mon chemin complet comme /media/MyDestination/data/Dir2/. J'ai ajouté --exclude pour empêcher la copie d'autres répertoires et fichiers dans /.
indiajoe du
Dans les cas où la liste des répertoires n'est pas très grande, je suppose que l'option suivante est plus facilersync -av $(cat DirectotiesToCopy.txt) /media/MyDestination/
indiajoe

Réponses:

6

Utilisez la commande suivante:

rsync -av --include-from=DirectoriesToCopy.txt --include /data/ --exclude='/data/*' --exclude='/*/' / /media/MyDestination/

Vous devez inclure / data / explicitement, vous auriez également pu l'ajouter à la liste du fichier. Ensuite, excluez tous les autres répertoires (l'ordre est important avec les inclusions / exclusions).

Notez que votre utilisation de -rétait redondante car elle est incluse dans -a.

EDIT: Vous pouvez également obtenir le même résultat avec:

rsync -av --relative /data/Dir1 /data/Dir2 /media/MyDestination/

Ce n'est pas rsync qui vous oblige à faire des choses difficiles juste pour copier quelques répertoires, il vous donne simplement plusieurs façons de faire la même chose; dans certains cas, le chemin d'inclusion / exclusion peut être plus adapté, ici je ferais la chose - relative ci-dessus (sans --relativevous vous retrouveriez avec /media/MyDestination/Dir1et /media/MyDestination/Dir2, avec le --relativechemin source entier est copié vers la destination).

Wurtel
la source
Merci qui a fonctionné. Je suis un peu surpris de devoir définir une séquence de filtres aussi soigneuse pour copier simplement une liste de répertoires à l'aide de rsync. Par exemple, si ma liste de répertoires n'était pas sous un seul répertoire / data / mais était plutôt répartie sur de nombreux emplacements, les filtres à définir deviennent assez compliqués.
indiajoe
Voir ma modification à ma réponse.
wurtel
Merci. Donc, si ma liste de répertoires n'est pas très grande, je pourrais utiliser l'indicateur --relative comme indiqué ci-dessous. rsync -av --relative $(cat DirectotiesToCopy.txt) /media/MyDestination/
indiajoe
Oui; garder à l'esprit --relativeest juste une autre option.
wurtel
7

Je veux utiliser rsync pour copier tous ces répertoires [à partir d'une liste] en préservant son chemin absolu vers un autre emplacement

N'utilisez pas --includeou des --filtervariations, car cela ne fera que confondre les choses. Utilisez plutôt --files-from=_filename_. (Si vous le faites, assurez-vous de faire beaucoup de tests.)

  1. Créez la liste des répertoires dans un fichier, un répertoire / fichier par ligne.

  2. Utilisez rsync --files-from=avec le fichier ci-dessus.

  3. Utilisez l' option --relative/ -Rpour vous assurer que les chemins d'accès source sont copiés à la fin de la destination.

  4. Même si vous en avez la -apossibilité, incluez également -r. Depuis la page de manuel:

    Dans les deux cas, si l'option -r était activée, la hiérarchie entière de ce répertoire serait également transférée (gardez à l'esprit que -r doit être spécifié explicitement avec --files-from, car il n'est pas impliqué par -a).

Commande complète:

rsync ${DEBUG:+-nv} -arR --files-from=<list_of_files.txt> <top-level-dir>  <target-dir>

(les fichiers dans list_of_files.txt doivent être relatifs ou trouvés dans le répertoire de niveau supérieur )

(si DEBUG est défini, rsync affiche simplement ce qui aurait pu être copié.)

Otheus
la source
1
Voilà ce dont j'avais besoin! Cependant "--include-from" devrait être "--files-from". J'ai également utilisé "--list-only" pour voir un aperçu de ce que RSYNC fera avant de le laisser fonctionner.
Adambean
1
Merci, j'ai mis à jour la réponse. --include-fromfonctionnera également, mais ce que j'ai dit -rest en grande partie hors de propos.
Otheus
2

Le manuel rsync met en garde contre ce scénario (section «Inclure / exclure les règles de modèle»):

cela ne fonctionnera pas:

+ /some/path/this-file-will-not-be-found
+ /file-is-included
- *

Cela échoue car le répertoire parent "some"est exclu par la '*'règle, donc rsync ne visite jamais aucun des fichiers des répertoires "some"ou "some/path". Une solution consiste à demander que tous les répertoires de la hiérarchie soient inclus en utilisant une seule règle: "+ */"(placez-la quelque part avant la "- *"règle), et utilisez peut-être l' --prune-empty-dirsoption. Une autre solution consiste à ajouter des règles d'inclusion spécifiques pour tous les répertoires parents à visiter. Par exemple, cet ensemble de règles fonctionne bien:

+ /some/
+ /some/path/
+ /some/path/this-file-is-found
+ /file-also-included
- *

Dans votre cas, je pense que l'approche la plus simple serait de prétraiter la liste des répertoires à inclure afin que chaque fois que vous incluez /path/to/foo, inclure également tous les répertoires parents ( /path/to, /path, /), et comprennent également les sous - répertoires des répertoires originaux ( /path/to/foo/***), et après tout cela a une règle qui exclut tout ce qui n'est pas répertorié précédemment ( *).

<DirectoriesToCopy.txt awk '
    {print "+ " $0 "/***"; while (sub(/\/+[^\/]+\/*$/, "/")) print "+ " $0}
    END {print "- *"}
' >rsync-rules.txt
rsync -avr --include-from=rsync-rules.txt  /  /media/MyDestination/
Gilles 'SO- arrête d'être méchant'
la source
Merci pour l'explication détaillée et le script pour créer le fichier de règles. Je comprends le problème maintenant. Je pense toujours qu'il aurait été bien pour rsync d'avoir une option comme --dirs-from = DirectoriesToCopy.txt comme raccourci vers tous les filtres compliqués.
indiajoe