rsync 使用文件列表作为变量

rsync 使用文件列表作为变量

我有两个文件,我想通过以下方式根据日期名称从远程 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 ...)——在命令替换(和变量引用)周围加上双引号通常是良好的脚本卫生习惯,以避免任何意外的单词拆分等。

相关内容