2009-11-28 17 views
16

como puede ver en el título, intento sincronizar una carpeta con una lista de archivos. Esperaba que este comando borrara todos los archivos en dest/que no están en la lista, pero no fue así.rsync --delete --files-from = list/dest/no elimina los archivos no deseados

Así que busqué un poco y ahora sé que rsync no puede hacer esto.

Pero lo necesito, ¿sabes alguna forma de hacerlo?

PD: La lista está creada por un script python, por lo que es imaginable que su solución use algún código python.

EDITAR, seamos concretos:

La lista se parece a esto:

/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 

y el comando de la siguiente manera:

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

Esto funciona, pero si elimino una línea, no se borra en foobar /.

EDIT 2:

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

que el trabajo ni ...

+0

Btw .: rsync versión 3.0.6 protocolo versión 30 se olvidó de eso, lo siento – dAnjou

+1

Una de las cosas que más odio de rsync, es la falta de soporte para exactamente lo que está pidiendo. Buen post. –

Respuesta

14

Tal vez usted podría hacer esto utilizando una lista de incluir patrones en su lugar, y utilizar --delete-excluded (que lo hace como su nombre indica)? Algo así como:

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

Si los nombres de archivo es probable que contengan caracteres comodín (*, ? y [) entonces es posible que tenga que modificar el pitón para escapar de ellos:

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

Editar: patronaje la coincidencia basada funciona de manera ligeramente diferente a --files-from en que rsync no se repetirá en directorios que coincidan con el patrón de exclusión, por razones de eficiencia.Así que si sus archivos están en /some/dir y /some/other/dir entonces su archivo de patrones tiene que quedar así:

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

Alternativamente, si todos los archivos están en el mismo directorio, entonces podría volver a escribir el comando ligeramente:

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

y luego sus patrones de convertirse:

/file1 
/file2 

Editar: Pensando en ello, que podría en clude todos los directorios con un solo patrón:

/**/ 

pero luego acabaría con el árbol de directorios en dest/ que probablemente no es lo que quiere. Pero combinándolo con -m (que poda directorios vacíos) debería resolver que - por lo que el comando termina algo como:

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

y el archivo de patrones:

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

Gracias, también, pero su comando pide -d o -r y ninguno funciona. – dAnjou

+0

En realidad, su comando no copia nada en dest/..: P – dAnjou

+1

¿Los archivos están en un subdirectorio? Si es así, el directorio (y sus padres) también deben estar en la lista de patrones, de lo contrario, rsync ni siquiera volverá a aparecer en ellos. – SimonJ

-1

rsync es ideal para mantener los directorios en sincronía, entre otras cosas útiles. Si tiene una copia exacta en el SOURCE y desea eliminar archivos en el DEST, puede eliminarlos de SOURCE y la opción rsync --delete también los eliminará de DEST.

Sin embargo, si sólo tienes una lista arbitraria de archivos que desea borrar, le sugiero que utilice SSH para lograrlo:

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

Esto ejecutará el comando rm en el host remoto.

usando Python, usted podría:

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

~ disfrutar

+1

Malentendido. No tengo una lista de archivos para eliminar. Tengo una lista de archivos para copiar. Quiero que los archivos que NO están en la lista sean eliminados. Pero gracias por su respuesta. – dAnjou

1

acumulación explícita --exclude-from = ... parece la única forma de sincronizar la lista de archivos.

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

Como se ha explicado, el comando

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

no elimina los contenidos en el destino cuando una entrada de $ FILELIST se ha eliminado. Una solución simple es usar en su lugar lo siguiente.

mkdir -p $DEST 
rm -rf $TEMP 
rsync -r --link-dest=$DEST --files-from=$FILELIST [email protected]:/ $TEMP/ 
rm -r $DEST 
mv $TEMP $DEST 

Esto indica a rsync que use un destino vacío. Los archivos que ya están presentes en el directorio link-dest están localmente vinculados y no se copian. Finalmente, el antiguo destino es reemplazado por el nuevo. El primer mkdir crea un $ DEST vacío si $ DEST no existe, para evitar el error de rsync. (Se supone que las $ -variables llevan la ruta completa al archivo o directorio respectivo.)

Hay algunos gastos generales menores para los enlaces duros, pero no es necesario que se meta con complejos include/exclude-strategies .

4

inspirado en M4T, pero usando rsync para la limpieza ...

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

¡gracias! buscó un tiempo para esa solución. –

+0

'rm -rf $ TEMP' es necesario antes de su código; de lo contrario, si $ temp tiene archivos no deseados, terminarán en $ dest. – kakyo

+0

Creo que hay un error tipográfico aquí, no estoy seguro de dónde –

0

realizo esta pregunta se le preguntó hace mucho tiempo, pero yo no estaba satisfecho con la respuesta.

Así es como he resuelto el problema, asumiendo una lista de reproducción creada por 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

Esto no es exactamente la solución, pero la gente que viene aquí podría resultar útil: Desde rsync 3.1.0 hay una --delete-missing-args parámetro que elimina archivos en el directorio de destino cuando sincroniza dos directorios usando --files-from.Lo que se necesita para especificar los archivos borrados en /tmp/list junto con archivos que desea copiar:

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

Ver the man page para más detalles.

Cuestiones relacionadas