bash rsync :递归同步所有文件,同时忽略目录结构

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14661033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:17:49  来源:igfitidea点击:

rsync : Recursively sync all files while ignoring the directory structure

bashrsync

提问by Srinath Sridhar

I am trying to create a bash script for syncing music from my desktop to a mobile device. The desktop is the source.

我正在尝试创建一个 bash 脚本,用于将音乐从我的桌面同步到移动设备。桌面是源。

Is there a way to make rsync recursively sync files but ignore the directory structure? If a file was deleted from the desktop, I want it to be deleted on the device as well.

有没有办法让 rsync 递归同步文件但忽略目录结构?如果文件从桌面上删除,我希望它也从设备上删除。

The directory structure on my desktop is something like this.

我桌面上的目录结构是这样的。

    Artist1/
        Artist1/art1_track1.mp3
        Artist1/art1_track2.mp3
        Artist1/art1_track3.mp3
    Artist2/
        Artist2/art2_track1.mp3
        Artist2/art2_track2.mp3
        Artist2/art2_track3.mp3
    ...

The directory structure that I want on the device is:

我想要在设备上的目录结构是:

    Music/
        art1_track1.mp3
        art1_track2.mp3
        art1_track3.mp3
        art2_track1.mp3
        art2_track2.mp3
        art2_track3.mp3
    ...

采纳答案by F. Hauri

Simply:

简单地:

rsync -a --delete --include=*.mp3 --exclude=* \
    pathToSongs/Theme*/Artist*/. destuser@desthost:Music/.

would do the job if you're path hierarchy has a fixed number of level.

如果您的路径层次结构具有固定数量的级别,则可以完成这项工作。

WARNING: if two song file do have exactly same name, while on same destination directory, your backup will miss one of them!

警告:如果两个歌曲文件的名称完全相同,而在同一目标目录中,您的备份将丢失其中之一!

If else, and for answering strictly to your ask ignoring the directory structureyou could use bash's shopt -s globstarfeature:

如果否则,并严格回答您的问题而忽略目录结构,您可以使用bashshopt -s globstar功能:

shopt -s globstar
rsync -a --delete --include=*.mp3 --exclude=* \
    pathToSongsRoot/**/. destuser@desthost:Music/.

At all, there is no need to fork to findcommand.

根本不需要 forkfind命令。

Recursively sync all files while ignoring the directory structure

递归同步所有文件,同时忽略目录结构

For answering strictly to question, there must no be limited to an extension:

对于严格回答问题,不能仅限于扩展:

shopt -s globstar
rsync -d --delete sourceRoot/**/. destuser@desthost:destRoot/.

With this, directories will be copied too, but without content. All files anddirectories would be stored on same level at destRoot/.

这样,目录也将被复制,但没有内容。所有文件目录都将存储在destRoot/.

WARNING: If some different files with same name exists in defferents directories, they would simply be overwrited on destination, durring rsync, for finaly storing randomly only one.

警告:如果不同的目录中存在一些具有相同名称的不同文件,它们将在目标上简单地被覆盖,在 rsync 期间,最终只随机存储一个。

回答by haridsv

May be this is a recent option, but I see the option --no-relativementioned in the documentation for --files-fromand it worked great.

可能这是一个最近的选项,但我看到--no-relative文档中提到的选项--files-from,它工作得很好。

find SourceDir -name \*.mp3 | rsync -av --files-from - --no-relative . DestinationDir/

回答by holgero

The answer to your question: No, rsynccannot do this alone. But with some help of other tools, we can get there... After a few tries I came up with this:

您的问题的答案:不,rsync不能单独完成此操作。但是在其他工具的帮助下,我们可以到达那里......经过几次尝试后,我想出了这个:

rsync -d --delete $(find . -type d|while read d ; do echo $d/ ; done) /targetDirectory && rmdir /targetDirectory/* 2>&-

The difficulty is this: To enable deletion of files at the target position, you need to:

难点在于:要启用删除目标位置的文件,您需要:

  1. specify directories as sources for rsync (it doesn't delete if the source is a list of files).
  2. give it the complete list of sources at once (rsyncwithin a loop will give you the contents of the last directory only at the target).
  3. end the directory names with a slash (otherwise it creates the directories at the target directory)
  1. 指定目录作为 rsync 的源(如果源是文件列表,则不会删除)。
  2. 一次给它完整的源列表(rsync在一个循环中只会给你目标上最后一个目录的内容)。
  3. 用斜杠结束目录名(否则它会在目标目录中创建目录)

So the command substitution (the stuff enclosed with the $()) does this: It finds all directories and adds a slash (/) at the end of the directory names. Now rsync sees a list of source directories, all terminated with a slash and so copies their contents to the target directory. The option -dtells it, not to copy recursively.

所以命令替换(用 括起来的东西$())这样做:它找到所有目录并在目录名称的末尾添加一个斜杠 (/)。现在 rsync 看到一个源目录列表,所有目录都以斜杠结尾,因此将它们的内容复制到目标目录。该选项-d告诉它,不要递归复制。

The second trick is the rmdir /targetDirectory/*which removes the empty directories which rsynccreated (although we didn't ask it to do that).

第二个技巧是rmdir /targetDirectory/*删除rsync创建的空目录(尽管我们没有要求它这样做)。

I tested that here, and deletion of files removed in the source tree worked just fine.

我在这里进行了测试,删除源树中删除的文件工作得很好。

回答by mariovials

If you can make a list of files, you've already solved the problem. Try:

如果您可以制作文件列表,那么您已经解决了问题。尝试:

find /path/to/src/ -name \*.mp3 > list.txt
rsync -avi --no-relative --progress --files-from=list.txt / user@server:/path/to/dest

If you run the script again for new files, it will only copy the missing files.

如果您为新文件再次运行该脚本,它只会复制丢失的文件。

If you don't like the list, then try a single sentence (but it's another logic)

如果你不喜欢这个列表,那就试试一个句子(但这是另一种逻辑)

find /path/to/src/ -name \*.mp3 -type f \
  -exec rsync -avi --progress {} user@server:/path/to/dest/  \;

In this case, you will ask for each file, each time, since by the type of sentence, you cannot build the file list previously.

在这种情况下,您每次都会询问每个文件,因为根据句子的类型,您之前无法构建文件列表。