2009-11-28 6 views
16

comme vous pouvez le voir dans le titre, j'essaie de synchroniser un dossier avec une liste de fichiers. J'espérais que cette commande supprimerait tous les fichiers de dest/qui ne sont pas dans la liste, mais ce n'est pas le cas.rsync --delete --files-from = liste/dest/ne supprime pas les fichiers indésirables

J'ai donc cherché un peu et je sais maintenant que rsync ne peut pas faire cela.

Mais j'en ai besoin, alors savez-vous un moyen de le faire? PS: La liste est créée par un script python, il est donc imaginable que votre solution utilise du code python.

EDIT, nous allons être concret:

La liste ressemble à ceci:

/home/max/Musik/Coldplay/Parachutes/Trouble.mp3 
/home/max/Musik/Coldplay/Parachutes/Yellow.mp3 
/home/max/Musik/Coldplay/A Rush of Blood to the Head/Warning Sign.mp3 
/home/max/Musik/Coldplay/A Rush of B-Sides to Your Head/Help Is Around the Corner.mp3 
/home/max/Musik/Coldplay/B-Sides (disc 3)/Bigger Stronger.mp3 

et la commande comme ceci:

rsync --delete --files-from=/tmp/list//home/max/Desktop/foobar/ 

Cela fonctionne, mais si je supprime une ligne, il n'est pas supprimé dans foobar /.

EDIT 2:

rsync -r --include-from=/tmp/list --exclude=* --delete-excluded//home/max/Desktop/foobar/ 

Ce travail ne ...

+0

Btw .: rsync version 3.0.6 protocole version 30 oublié, désolé – dAnjou

+1

Une des choses que je déteste le plus à propos de rsync, est ce manque de soutien pour exactement ce que vous demandez. Bon post. –

Répondre

14

Peut-être que vous pourriez le faire en utilisant une liste d'inclure des modèles au lieu, et utiliser --delete-excluded (qui fait comme son nom l'indique)? Quelque chose comme:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded/dest/ 

Si les noms de fichiers sont susceptibles de contenir des caractères génériques (*, ? et [), vous devrez peut-être modifier le Python pour leur échapper:

re.sub("([[*?])", r"\\\1", "abc[def*ghi?klm") 

Edit: Pattern L'appariement basé fonctionne légèrement différemment à --files-from en ce que rsync ne se recurdera pas dans les répertoires qui correspondent au modèle d'exclusion, pour des raisons d'efficacité.Donc, si vos fichiers sont en /some/dir et /some/other/dir alors vos besoins de fichier modèle pour ressembler à:

/some/ 
/some/dir/ 
/some/dir/file1 
/some/dir/file2 
/some/other/ 
/some/other/dir/ 
/some/other/dir/file3 
... 

Alternativement, si tous les fichiers sont dans le même répertoire, vous pouvez réécrire la commande légèrement:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded /some/dir/ dest/ 

puis vos habitudes deviennent:

/file1 
/file2 

Edit: en y repensant, vous pourriez en Clude tous les répertoires avec un motif:

/**/ 

mais vous finiriez avec l'arborescence de répertoires dans dest/ ce qui est probablement pas ce que vous voulez. Mais la combinaison avec -m (qui émonde les répertoires vides) doivent résoudre ce - si la commande finit par quelque chose comme:

rsync -m -r --delete-excluded --include-from=<patternfile> --exclude=*/dest/ 

et le fichier de configuration:

/**/ 
/some/dir/file1 
/some/other/dir/file3 
+0

Merci aussi, mais votre commande demande -d ou -r et ne fonctionne pas. – dAnjou

+0

En fait, votre commande ne copie rien à dest/..: P – dAnjou

+1

Les fichiers sont-ils dans un sous-répertoire? Si tel est le cas, le répertoire (et ses parents) doivent également figurer dans la liste des patterns, sinon rsync ne les recurera même pas. – SimonJ

-1

rsync est idéal pour garder les répertoires synchronisés, entre autres choses utiles. Si vous avez une copie exacte sur la SOURCE, et que vous voulez supprimer des fichiers sur DEST, vous pouvez les supprimer de SOURCE et l'option rsync --delete les supprimera également de DEST.

Cependant, si vous avez juste une liste arbitraire de fichiers que vous souhaitez supprimer, je vous suggère d'utiliser SSH pour y parvenir:

ssh [email protected] rm /path/to/file1 /path/to/file2 

Cela exécutera la commande rm sur l'hôte distant.

En utilisant python, vous pouvez:

import subprocess 
FileList = ['/path/to/file1', '/path/to/file2'] 
subprocess.call(['ssh', '[email protected]', 'rm'] + FileList) 

~ profiter

+1

Malentendu. Je n'ai pas de liste de fichiers à supprimer. J'ai une liste de fichiers à copier. Je veux que les fichiers qui ne sont pas sur la liste soient supprimés. Mais merci pour votre réponse. – dAnjou

1

build explicite --exclude-from = ... semble le seul moyen de synchroniser la liste des fichiers.

stdin = subprocess.PIPE 
other_params.append("--exclude-from=-") #from stdin 

p = subprocess.Popen('rsync -e ssh -zthvcr --compress-level=9 --delete'.split() + other_params + [src, dst], stdin = PIPE) 

if relative_files_list != None: 
    #hack: listing of excluded files seems the only way to delete unwanted files at destination 
    files = set(map(norm_fn, relative_files_list)) #make hash table, for huge lists 
    for path, ds, fs in os.walk(src): 
     for f in fs: 
      rel_path_f = norm_fn(os.path.relpath(os.path.join(path, f), src)) 
      if rel_path_f not in files: 
       #print 'excluding', rel_path_f.replace('\\', '/') 
       p.stdin.write(rel_path_f + '\n') 
    p.stdin.close() 
assert 0 == p.wait() 
6

Comme vous l'avez expliqué, la commande

rsync -r --delete --files-from=$FILELIST [email protected]:/ $DEST/ 

ne supprime pas le contenu de la destination lors d'une entrée de $ FILELIST a été supprimé. Une solution simple est d'utiliser à la place ce qui suit.

Cette commande indique à rsync d'utiliser une destination vide. Les fichiers déjà présents dans le répertoire link-dest sont localement liés et non copiés. Enfin, l'ancienne destination est remplacée par la nouvelle. Le premier mkdir crée un $ DEST vide si $ DEST n'existe pas, pour éviter une erreur rsync. (Les $ -variables sont supposés porter le chemin complet vers le fichier ou le répertoire respectif.)

Il y a un léger surcoût pour la liaison physique, mais vous n'avez pas besoin de manipuler des stratégies d'inclusion/exclusion complexes. .

4

Inspirée de M4T, mais en utilisant ... rsync pour le nettoyage

rsync -r --link-dest=$dst --files-from=filelist.txt [email protected]:$source/ $temp 
rsync -ra --delete --link-dest=$temp $temp/ $dest 
+0

thx! cherché un moment pour cette solution. –

+0

'rm -rf $ TEMP' est nécessaire avant votre code, sinon, si $ temp contient des fichiers non désirés, ils finiront par $ dest. – kakyo

+0

Je pense qu'il ya une faute de frappe ici, pas exactement sûr où –

0

Je me rends compte de cette question a été posée il y a longtemps, mais je n'étais pas satisfait de la réponse.

Voici comment je l'ai résolu le problème, en supposant une playlist créée par mpd:

#!/bin/bash                 

playlist_path="/home/cpbills/.config/mpd/playlists" 
playlist="${playlist_path}/${1}.m3u" 
music_src="/home/cpbills/files/music" 
music_dst="/mnt/sdcard/music/" 

if [[ -e "$playlist" ]]; then 
    # Remove old files 
    find "$music_dst" -type f | while read file; do 
    name="$(echo "$file" | sed -e "s!^$music_dst!!")" 
    if ! grep -qF "$name" "$playlist"; then 
     rm "$file" 
    fi 
    done 

    # Remove empty directories 
    find "$music_dst" -type d -exec rmdir {} \; 2>/dev/null 

    rsync -vu \ 
     --inplace \ 
     --files-from="$playlist" \ 
     "$music_src" "$music_dst" 
else 
    printf "%s does not exist\n" "$playlist" 1>&2 
    exit 1 
fi 
8

Ce n'est pas exactement la solution, mais les gens à venir pourraient trouver ici ce utile: Depuis rsync 3.1.0 il y a un --delete-missing-args paramètre qui supprime des fichiers dans le répertoire de destination lorsque vous synchronisez deux répertoires en utilisant --files-from.Vous devrez spécifier les fichiers supprimés dans /tmp/list ainsi que des fichiers que vous ne souhaitez copier:

rsync --delete-missing-args --files-from=/tmp/list /source/dir /destination/dir 

Voir the man page pour plus de détails.