Rsync --delete --files-from = list/dest/не удаляет ненужные файлы

Как видно из названия, я пытаюсь синхронизировать папку со списком файлов. Я надеялся, что эта команда удалит все файлы в dest/, которых нет в списке, но этого не произошло.

Поэтому я немного искал и теперь знаю, что rsync не может этого сделать.

Но мне это нужно, так вы знаете, как это сделать?

PS: список создается скриптом Python, поэтому можно представить, что ваше решение использует некоторый код Python.

РЕДАКТИРОВАТЬ, пусть будет конкретным:

Список выглядит так:

/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

и команда, как это:

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

Это работает, но если я удаляю строку, она не удаляется в foobar/.

РЕДАКТИРОВАТЬ 2:

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

Это тоже не работает...

Ответы

Ответ 1

Возможно, вы могли бы сделать это, используя вместо этого список включенных шаблонов, и использовать --delete-excluded (что делает, как следует из названия)? Что-то вроде:

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

Если имена файлов, вероятно, содержат подстановочные знаки (*, ? и [), вам может потребоваться изменить Python, чтобы избежать их:

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

Изменить: Согласование на основе шаблонов несколько отличается от --files-from тем, что rsync не будет возвращаться в каталоги, соответствующие шаблону исключения, по соображениям эффективности. Поэтому, если ваши файлы находятся в /some/dir и /some/other/dir, тогда ваш файл шаблонов должен выглядеть так:

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

В качестве альтернативы, если все файлы находятся в одном каталоге, вы можете немного переписать команду:

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

а затем ваши шаблоны станут:

/file1
/file2

Изменить: Думая об этом, вы можете включить все каталоги с одним шаблоном:

/**/

но затем вы получите полное дерево каталогов в dest/, которое, вероятно, не то, что вы хотите. Но объединение этого параметра с -m (которое создает пустые каталоги) должно решить это - так что команда заканчивается примерно так:

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

и файл шаблона:

/**/
/some/dir/file1
/some/other/dir/file3

Ответ 2

Это не совсем то решение, но люди, пришедшие сюда, могут найти это полезным: поскольку rsync 3.1.0 имеет параметр --delete-missing-args, который удаляет файлы в каталоге назначения при синхронизации двух каталогов с помощью --files-from. Вам нужно будет указать удаленные файлы в /tmp/list вместе с файлами, которые вы хотите скопировать:

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

Подробнее см. справочную страницу.

Ответ 3

Как вы объяснили, команда

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

не удаляет контент в получателе, когда была удалена запись из $FILELIST. Простое решение заключается в следующем:

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

Это указывает rsync использовать пустую адресату. Файлы, которые уже присутствуют в каталоге link-dest, локально жестко связаны и не копируются. Наконец, старый пункт назначения заменяется новым. Первый mkdir создает пустой $DEST, если $DEST не существует, чтобы предотвратить ошибку rsync. (Предполагается, что $-variables несут полный путь к соответствующему файлу или каталогу.)

Есть некоторые незначительные накладные расходы для жесткой привязки, но вам не нужно возиться со сложными include/exclude-strategy.

Ответ 4

Вдохновленный из m4t, но используя... rsync для очистки

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

Ответ 5

Явная сборка --exclude-from =... кажется единственным способом синхронизации списка файлов.

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

Я понимаю, что этот вопрос был задан давно, но я не был удовлетворен ответом.

Вот как я решил проблему, принимая плейлист, созданный 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

Ответ 7

rsync идеально подходит для хранения каталогов в синхронизации, среди других полезных вещей. Если у вас есть точная копия на SOURCE и вы хотите удалить файлы в DEST, вы можете удалить их из SOURCE, а опция rsync --delete также удалит их из DEST.

Однако, если у вас есть только произвольный список файлов, которые вы хотите удалить, я предлагаю вам использовать SSH для этого:

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

Это приведет к выполнению команды rm на удаленном хосте.

Используя python, вы можете:

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

~ наслаждаться