rsync --delete --files-from = list / dest /不会删除不需要的文件

时间:2009-11-28 22:01:57

标签: rsync

正如您在标题中看到的,我尝试将文件夹与文件列表同步。我希望这个命令会删除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 个答案:

答案 0 :(得分:15)

也许您可以使用包含模式列表来执行此操作,并使用--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

答案 1 :(得分:10)

这不完全是解决方案,但是来到这里的人可能会觉得这很有用:因为rsync 3.1.0有一个--delete-missing-args参数,当你使用{{1}同步两个目录时删除目标目录中的文件}。您需要在--files-from中指定已删除的文件以及要复制的文件:

/tmp/list

有关详细信息,请参阅the man page

答案 2 :(得分:6)

正如你解释的那样,命令

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中已存在的文件是本地硬链接的,不会被复制。最后,旧目的地被新的目的地取代。如果$ DEST不存在,则第一个mkdir创建一个空的$ DEST,以防止rsync错误。 (假定$ -variables携带到相应文件或目录的完整路径。)

硬链接有一些小的开销,但你不需要搞乱复杂的包含/排除策略。

答案 3 :(得分:4)

受到m4t的启发,但使用... rsync进行清理

rsync -r --link-dest=$dst --files-from=filelist.txt user@server:$source/ $temp
rsync -ra --delete --link-dest=$temp $temp/ $dest

答案 4 :(得分:1)

显式构建--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()

答案 5 :(得分:0)

我很久以前就意识到这个问题,但我对答案不满意。

假设由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

答案 6 :(得分:-1)

rsync 非常适合保持目录同步,以及其他有用的东西。如果您在SOURCE上有确切的副本,并且想要删除DEST上的文件,您可以从SOURCE中删除它们,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)

〜享受