正如您在标题中看到的,我尝试将文件夹与文件列表同步。我希望这个命令会删除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/
那项工作既不......
答案 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)
〜享受