29

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

这既不工作......

4

7 回答 7

22

也许您可以改为使用包含模式列表来执行此操作,并使用--delete-excluded(顾名思义)?就像是:

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

如果文件名可能包含通配符(和) *,那么您可能需要修改 Python 以转义它们:?[

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

编辑:基于模式的匹配与不会递归到匹配排除模式的目录的工作方式略有不同--files-fromrsync出于效率的原因。因此,如果您的文件在/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
于 2009-11-28T22:29:29.383 回答
12

这不完全是解决方案,但来到这里的人可能会发现这很有用:由于 rsync 3.1.0 有一个--delete-missing-args参数,当您使用--files-from. 您需要指定已删除的文件/tmp/list以及要复制的文件:

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

有关更多详细信息,请参见手册页

于 2015-06-12T15:17:57.877 回答
10

正如你所解释的,命令

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 带有相应文件或目录的完整路径。)

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

于 2013-03-03T23:20:51.363 回答
4

灵感来自 m4t,但使用 ... rsync 进行清理

rsync -r --link-dest=$dst --files-from=filelist.txt user@server:$source/ $temp
rsync -ra --delete --link-dest=$temp $temp/ $dest
于 2013-03-13T11:23:38.433 回答
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()
于 2010-11-03T13:45:16.693 回答
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
于 2015-02-01T01:37:05.657 回答
-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)

~享受

于 2009-11-28T22:23:23.950 回答