rsync --delete --files-from = list / dest / не удаляет ненужные файлы - PullRequest
22 голосов
/ 29 ноября 2009

Как видно из названия, я пытаюсь синхронизировать папку со списком файлов. Я надеялся, что эта команда удалит все файлы в 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/

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

Ответы [ 7 ]

16 голосов
/ 29 ноября 2009

Возможно, вы могли бы сделать это, используя вместо этого список шаблонов включения, и использовать --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
10 голосов
/ 12 июня 2015

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

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

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

6 голосов
/ 04 марта 2013

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

rsync -r --delete --files-from=$FILELIST user@server:/ $DEST/

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

mkdir -p $DEST
rm -rf $TEMP
rsync -r --link-dest=$DEST --files-from=$FILELIST user@server:/ $TEMP/
rm -r $DEST
mv $TEMP $DEST

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

Существуют незначительные накладные расходы для жестких ссылок, но вам не нужно возиться со сложными стратегиями включения / исключения.

4 голосов
/ 13 марта 2013

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

rsync -r --link-dest=$dst --files-from=filelist.txt user@server:$source/ $temp
rsync -ra --delete --link-dest=$temp $temp/ $dest
1 голос
/ 03 ноября 2010

Явная сборка --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()
0 голосов
/ 01 февраля 2015

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

Вот как я решил проблему, предполагая, что плейлист создан 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
0 голосов
/ 29 ноября 2009

rsync идеально подходит для синхронизации каталогов, среди других полезных вещей. Если у вас есть точная копия на ИСТОЧНИКЕ и вы хотите удалить файлы в DEST, вы можете удалить их из ИСТОЧНИКА и опция rsync --delete также удалит их из DEST.

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

ssh user@remote.host.com rm /path/to/file1 /path/to/file2

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

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

import subprocess
FileList = ['/path/to/file1', '/path/to/file2']
subprocess.call(['ssh', 'dAnjou@my.server.com', 'rm'] + FileList)

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

...