下面是 Ubuntu 18.04 上的一个脚本,用于将文件从一个目录复制到另一个目录。除了当前目录 ( ) 中的文件/media/rmerriam/Backup/rsync_backup
被复制到目标之外,一切正常。它们根本不应该被复制,因为它们从来不在源路径中。
手动执行(有或没有没有-s
区别):
rmerriam@mysticlakelinux:/media/rmerriam/test/rsync_backup$ rsync -auv -s ../src/ ../dest
sending incremental file list
sent 59 bytes received 12 bytes 142.00 bytes/sec
total size is 0 speedup is 0.00
rmerriam@mysticlakelinux:/media/rmerriam/test/rsync_backup$ ls ../dest
执行的脚本没有-s
:
===========================
./merge.sh
../src/
../dest
rsync -auv ../src/ ../dest
sending incremental file list
./ <====== added why???
merge.sh
merge_all.sh
merge_backups.sh
sent 3,124 bytes received 76 bytes 6,400.00 bytes/sec
total size is 2,835 speedup is 0.89
rmerriam@mysticlakelinux:/media/rmerriam/test/rsync_backup$ ls ../dest
merge_all.sh merge_backups.sh merge.sh
使用-s
选项执行脚本:
rmerriam@mysticlakelinux:/media/rmerriam/test/rsync_backup$ ./merge.sh ../src/ ../dest -s
===========================
./merge.sh
-s
../src/
../dest
rsync -auv -s ../src/ ../dest
sending incremental file list
./
sent 66 bytes received 19 bytes 170.00 bytes/sec
total size is 0 speedup is 0.00
rmerriam@mysticlakelinux:/media/rmerriam/test/rsync_backup$ ls ../dest
结果:手动执行和-s
选项没有移动$PWD
文件。如果没有-s
脚本,则复制文件。
该脚本没有-s
添加该./
目录作为源目录。为什么?
命令行由 所示,echo
并且它们是相同的。为什么脚本中有不同的行为?
这是脚本:
#!/bin/bash
# base script for copying files to the common directory.
# only copies newer files
printf '===========================\n'
printf "$0\n $3\n $1\n $2\n"
echo rsync -auv "$3" "$1" "$2"
rsync -auv "$3" "$1" "$2"
以供参考 :rsync version 3.1.2 protocol version 31
答案1
你的脚本中有一个错误。可以说,rsync 中也存在一个错误,因为当你向它传递奇怪的数据时,它会默默地做一些令人惊讶的事情,而最好让它出错。但无论哪种方式,你的脚本都不起作用。
有问题的行是:
rsync -auv "$3" "$1" "$2"
当脚本 ( "$3"
) 的第三个参数以 a 开头时-
,这是 rsync 的一个选项。但是,当第三个参数不以 a 开头时-
(包括脚本只有两个参数(或更少)的情况),这是一个非选项参数。 Rsync 接受多个源目录,因此当"$3"
不以 a 开头时-
,您要求它复制"$3"
并"$1"
到"$2"
.例如,
./merge.sh ../src/ ../dest
告诉 rsync 将空字符串复制../src/
到../dest
.
大多数应用程序在查找文件名时都会拒绝空字符串。但是,只要接受空字符串作为文件名,它就表示当前目录。它与相对路径转换为绝对路径的方式一致:如果路径是相对路径(不以 开头/
),则在当前工作目录的绝对路径和斜杠前面加上斜杠,您将获得等效的绝对路径。如果将此应用于空字符串(由于它不以斜杠开头,所以它是相对路径),您将获得末尾带有斜杠的当前工作目录,即当前工作目录。
Rsync 接受空字符串作为当前目录。所以它完全按照你所说的去做。
可以说,将空字符串作为参数传递更有可能是一个错误,而不是故意的。指定当前目录的最短且广泛接受的方式是.
(点)。因此,可以说 rsync 应该打印一条错误消息,指出参数无效并出错。
您希望您的脚本接受可选的额外选项,但按照您实现它的方式,该额外选项是强制性的。要使其可选,请检查脚本是否有第三个参数。
if [ $# -lt 2 ]; then
echo >&2 "$0: too few arguments (SRC and DEST are required)"
exit 120
elif [ $# -eq 2 ]; then
rsync -auv "$1" "$2"
elif [ $# -eq 3 ]; then
rsync -auv "$3" "$1" "$2"
else
echo >&2 "$0: too many arguments (only one OPTIONS argument is permitted)"
exit 120
fi
但这是一个奇怪的界面:为什么最多接受一个选项?你不妨接受任意数量的选项(为什么我不能通过-q --dry-run
?)。对于用户来说,这既更容易理解,也更容易实现。此外,约定是传递选项前非选项参数,而不是之后。一旦界面被简化为接受任意数量的选项,您可以将代码简化为
rsync -auv "$@"
答案2
去查看问题rsync
并发现“空引号将 cwd 添加到 SRC 目录”。我$3
对添加额外选项的脚本有争议。通常它是空的,所以这是罪魁祸首。添加-s
使得参数非空,因此避免了这个问题。
这次手动运行证实了这个问题:
rsync "" -auv ../src/ ../dest
sending incremental file list
created directory ../dest
./
merge.sh
merge_all.sh
merge_backups.sh
sent 3,124 bytes received 106 bytes 6,460.00 bytes/sec
total size is 2,835 speedup is 0.88