使用 rsync 仅复制包含 .mp3 文件的目录

使用 rsync 仅复制包含 .mp3 文件的目录

我试图仅将其中包含 .mp3 文件的文件夹复制到另一台设备。并且只有其中的 .mp3。结构如下:

Band/Year - Album/*.flac
Band/Year - Album/*.txt
Band/Year - Album/*.mp3
Band/Year - Album/covers
Band/Year - Album/covers/*.jpg

我已经阅读了大量手册和论坛,但无法解决我的问题。无论我做什么,无论我如何尝试制定我想在复制中包含的内容,因为它被排除在外 - 它甚至消失了

--exclude=* --include=*

不会复制任何东西。我在另一个目录上测试了它,即使没有任何目录,该死。

编辑:我尝试过但无济于事的列表:

rsync -rnv --exclude=** --include=*/ --include=*/*/ --include=*/*/*/ --include=*/*/*.mp3 "./Be'lakor" /media/moorindal/WALKMAN/MUSIC
rsync -rnv --exclude=** --include=*/ --include=*/*/ --include=*/*/*/ --include=**.mp3 "./Be'lakor" /media/moorindal/WALKMAN/MUSIC
rsync -rnv --exclude=** --include=*/ --include=*/* --include=**.mp3 "./Be'lakor" /media/moorindal/WALKMAN/MUSIC
rsync -rnv --exclude=*/*/* --include=**.mp3 "./Be'lakor" /media/moorindal/WALKMAN/MUSIC
rsync -rnv --exclude=*/*/*.* --include=**.mp3 "./Be'lakor" /media/moorindal/WALKMAN/MUSIC
rsync -rnv --exclude='*/*/*.*' --include='*/*/*.mp3' "./Be'lakor" /media/moorindal/WALKMAN/MUSIC

答案1

首先,为什么--exclude=* --include=*不起作用:因为第一个匹配规则适用。*匹配所有内容,因此所有内容都被排除,并且 rsync 甚至不会对任何文件尝试第二条规则。看Rsync 过滤器:仅复制一种模式有关 rsync 过滤器的指南。

要包含.mp3文件,您需要

rsync -a -m --include='*.mp3' --include='*/' --exclude='*'

即包括 MP3,包括所有目录(如果不包括目录,则不包括其中的任何文件)并排除其他所有内容。该-m选项(又名--prune-empty-dirs)使 rsync 跳过不包含任何要复制的文件的目录。但这不会包含与该.mp3文件位于同一目录中的其他文件。为此,您需要 shell 或其他工具的帮助。

在 zsh 中,您可以将.mp3子目录中的文件与匹配**/*.mp3,然后使用历史修改器作为一个全局限定符将结果转换为包含.mp3文件的目录列表。

rsync -a **/*.mp3(:h) /destination

如果您有太多目录(或者更准确地说,如果它们名称的组合长度太大),这可能会打破命令行限制。删除重复项可能会有所帮助:

typeset -aU directories
directories=(**/*.mp3(:h))
rsync -a $directories /destination

这并不能消除命令过长的风险,而只是减少了风险。为了消除风险,请使用zargs批量运行rsync。

autoload -U zargs
typeset -aU directories
directories=(**/*.mp3(:h))
do_rsync () { rsync -a $@ /destination; }
zargs --max-chars=$(($(get_conf ARG_MAX) - 500)) -- $directories -- do_rsync

答案2

您想用 rsync 做太多事情。首先要做的是生成所有 MP3 文件的列表。

find Music -type f -iname '*.mp3'

然后将文件列表转换为包含文件的目录列表。

sed 's:/[^/]*$::'

消除列表中任何重复的目录。

sort -u

现在您已获得所需的目录列表。一次将它们喂给 rsync 一个。使用 --relative 保持目标目录树完整。

while IFS= read -r dir; do rsync --archive --relative "$dir" /mnt; done

总共作为一个管道:

find Music -type f -iname '*.mp3' |
   sed 's:/[^/]*$::' |
   sort -u |
   while IFS= read -r dir; do rsync --archive --relative "$dir" /mnt; done

答案3

您无需担心--include--exclude为这种情况而烦恼。只需告诉rsync复制mp3位于结构良好的已知位置的文件即可:

cd /path/to/source
rsync -avR */*/*.mp3 /path/to/target/

也许您想复制包含mp3.您可以通过这个小循环来做到这一点,再次假设结构良好的布局:

for mp3 in */*/*.mp3
do
    rsync --exclude covers -avR "${mp3%/*}"/ /path/to/target/
done

相关内容