Linux rsync 命令

2017-12-27|Categories: External cmd|

常用选项

选项 用途
-n,
--dry-run
仅模拟执行,而不会真的修改
-a,
--archive
Archive mode, equals -rlptgoD (no -H,-A,-X)
-h 把数字输出为人类易读的格式
-i,
--itemize-changes
列出源目录和目标目录文件不同之处
-v verbose
-z 压缩文件数据后传输
-e 指定传输协议,
例如通过非标准ssh端口传输:rsync -e 'ssh -p <port_num>'
--delete 从目标目录删除那些仅在目标目录有,而源目录没有的文件或目录
--max-size= 只传输小于或等于指定大小的文件
--bwlimit= 限制传输速度,默认单位KiB/s
--ignore-existing 不更新目标目录已有的文件
--existing 更新目标目录已有的文件,但不创建新文件或目录
--remove-source-files 传输成功后删除源文件
--progress 对每个文件都显示文件大小、传输速度、剩余时间

脚本示例

这个脚本用于在macOS系统自动挂载「马哥教育27期Linux培训班」的samba共享文件夹,然后用rsync同步其中的slides/目录下所有文件到本机指定目录。

#!/usr/bin/env bash
#
#===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
# Filename:     sync_magedu_textbooks.sh
# Revision:     1.0
# Date:         2017-12-16
# Description:
# Author:       Li Yang
# Website:      https://liyang85.com
#===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== =====

pdfSrc="${HOME}/magedu_smb/slides"
# delete `/slides` of $pdfSrc then assign to $smbSrc
smbSrc=${pdfSrc%/*}
dest="${HOME}/Google 云端硬盘/magedu-linux-training-27/pdf/"

[ `uname` == "Darwin" ] \
    || { echo "Please run this script on macOS." && exit 1; }

[ -d "${smbSrc}" ] || mkdir "${smbSrc}"

# the path of remote samba shared directory is 172.18.0.1/27,
# if a line of `df` output contains the path and the last field equal to
# $smbSrc, that means the samba shared dir has been mounted on $smbSrc.
[[ "`df | awk '/172\.18\.0\.1\/27/{print $NF}'`" == "${smbSrc}" ]] \
    || /sbin/mount -t smbfs //magedu27:magedu27@172.18.0.1/27 "${smbSrc}"

# 源目录末尾有斜线`/`表示只传输目录下所有文件,而 不包括 源目录本身;
# 如果没有斜线,将 包括 源目录本身
default="rsync -ahivz"
${default} --dry-run "${pdfSrc}/" "${dest}"

echo -e "\n===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"
read -rp "The dry-run result showed above, continue to really sync them? [y/n] " -n1
echo

if [[ $REPLY = [YyNn] ]]; then
    if [[ $REPLY = [Yy] ]]; then
        # there must be a slash (/)
        ${default} "${pdfSrc}/" "${dest}"
    else
        echo -e "\nYou have to manual run rsync with different options, current are: \n${default}"
        exit 2
    fi
fi

注意事项

  • rsync默认自动创建目录。
  • 即使之前没有使用rsync同步过,改用rsync仍然会检查源目录和目标目录的差异,相同文件不会同步。
  • rsync会检查文件的内容、权限、mtime,两个文件任意一项不同都会被认为是不同的,所以在上面这个脚本中,应当使用-a选项同步所有属性,而不是-r,否则即使内容相同,mtime不同也会导致重复同步。

根据指定的列表同步文件

实现这个功能的选项是--files-from=,等号后面是文件路径,存放要复制的文件的列表,完整语法如下:

rsync --files-from=FILE src_path_beginning dest

这里的关键是src_path_beginning,这是一个绝对路径,会被添加到文件列表每一行的开头。例如文件列表${HOME}/dotfiles.lst包含如下内容:

.bash_profile
.vimrc

如果rsync命令如下:

rsync --files-from="${HOME}/dotfiles.lst" ${HOME} "${HOME}/bak-dotfiles"

执行这条命令时,${HOME}会被添加到每行文件列表的开头:

${HOME}/.bash_profile
${HOME}/.vimrc

然后再把修改路径之后的文件${HOME}/.bash_profile同步到${HOME}/bak-dotfiles

完整代码(函数)如下,我需要在~/dotfiles目录下执行对应的脚本,find .就是搜索这个目录。

bakDotfiles() {
    bakDir="bak-dotfiles"
    fullBakDir="${HOME}/${bakDir}"
    [ -d "${fullBakDir}" ] || mkdir -p "${fullBakDir}"

    dotfiles="${HOME}/dotfiles.lst"
    find . -mindepth 1 -path "./.git" -prune -or -print > "${dotfiles}"

    # the output of `find .` always like `./found_file`,
    # delete the dot at the beginning of every line
    sed -i 's/^\.//' "${dotfiles}"

    # ${HOME} will be added to the beginning of every line of $dotfiles
    # in the other words, this would expect the paths to be relative 
    # to the source location of ${HOME} and would retain the entire
    # absolute structure under that destination.
    rsync -a --files-from="${dotfiles}" ${HOME} "${fullBakDir}" &>/dev/null
}

Leave A Comment