我有两个文件,我想通过以下方式根据日期名称从远程 samba 共享进行 rsync :
older="/path/to/file/"$(date -d '2 days ago' '+%Y%m%d')*.pdf
old="/path/to/file/"$(date -d yesterday '+%Y%m%d')*.pdf
rsync -ahvz "$old $older" /destination
似乎文件名变量没问题,但是 rsync 给出了一个错误:
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1207) [sender=3.1.3]
如果我检查文件存在,则没有问题:
ls -lah $older
rwxrwxrwx 553M forge 21 Aug 11:57 20210821.pdf
答案1
问题在于您的引用。文件路径变量 ( "$old $older"
) 周围的双引号告诉 shell 将两者视为单个项目,同时还阻止它将通配符 ( *
) 扩展为匹配文件的实际名称。因此,它在精确路径“ /path/to/file/20210822*.pdf /path/to/file/20210821*.pdf
”处查找单个文件(并且要清楚的是,该路径包含一个名为“ 20210822*.pdf
”的目录,包括名称末尾的文字星号字符和空格)。
现在,如果路径不包含任何实际的奇怪字符(例如文件/目录名称中的空格),您可以完全删除双引号,这样 shell 就会将变量视为单独的项目并扩展通配符:
rsync -ahvz $old $older /destination
但如果你和我一样,在文件/目录名称中出现空格的环境中工作,那么这种方法就行不通了,因为路径会根据这些空格(或某些其他字符)被拆分成多个项目(“单词”)。在这种情况下,你需要用双引号将不应拆分的部分括起来,并且不是通配符周围有双引号,并且不能部分引用变量。
(人们经常尝试通过在变量的值中嵌入引号和/或转义来解决此类问题,以尝试控制拆分和扩展。它不起作用。不要试图让它发挥作用,这只是错误的做事方式。)
在 bash 中(但没有数组的更基本的 shell 中),处理此问题的更好方法是立即扩展通配符,并将匹配名称的列表存储为数组:
older=("/path/to/file/$(date -d '2 days ago' '+%Y%m%d')"*.pdf)
old=("/path/to/file/$(date -d yesterday '+%Y%m%d')"*.pdf)
rsync -ahvz "${old[@]}" "${older[@]}" /destination
这里,赋值语句中的括号组成了older
数组old
而不是普通的变量(即使每个变量只有一个匹配的文件,那么它们只是一个元素数组),并且语法"${arrayname[@]}"
告诉 shell 获取数组的所有元素,但不要对它们做任何愚蠢的事情。
另外,请注意,在数组声明中,我用双引号括住了路径的固定前缀,还有部分$(date ...)
——在命令替换(和变量引用)周围加上双引号通常是良好的脚本卫生习惯,以避免任何意外的单词拆分等。