我正在尝试在bash脚本内的单个调用中rsync多个目录,并且使用引用路径的语法遇到了麻烦。
以下是我的尝试:
backuppath='/path/to/backup/folders/'
declare -a backupitems=('folder1' 'folder2')
backupitems=(${backupitems[@]/#/\"$backuppath})
backupitems=(${backupitems[@]/%/\"})
backup=${backupitems[@]}
rsync ${backup} /path/to/destination
我收到一个link_stat错误,指出"/path/to/current/directory"/path/to/backup/folders/folder1""
没有这样的文件或目录,然后是folder2的相同错误。所以看起来它像我想要的那样生成引用路径,但是rsync将路径解释为相对路径并添加到前面当前目录的路径上。如果我这样做,rsync可正常工作
backuppath='path/to/backup/folders/folder1'
rsync "${backuppath}" /path/to/destination
将引号放入rsync命令,但我不能在一个变量中使用多个文件夹,因为它将多个目录视为一个长的单一路径。我通过循环文件夹并在每个文件夹上调用rsync来使用第二种方法使用脚本工作,但是由于脚本的其他部分处理文件夹的方式所以我希望得到第一种方法,这种方法稍微有些尴尬如果有快速解决方法可以工作。
修改
对于上面的顶级版本,在任何目录名称中都没有空格,我使用set -vx
看到以下命令:
rsync'“/ path / to / backup / folders / folder1”''“/ path / to / backup / folders / folder2”'/ path / to / destination
我收到以下错误消息:
rsync: link_stat "/path/to/current/directory/"/path/to/backup/folders/folder1"" failed: No such file or directory (2)
如果我使用@kdubs建议的版本,那么当路径中没有空格时,一切都有效。
当路径中有空格时,kdubs版本会生成命令:
rsync / path / to / back up / folders / folder1 / path / to / back up / folders / folder2 / path / to / destination
和错误:
rsync: link_stat "/path/to/back" failed: No such file or directory (2)
rsync: link_stat "/path/to/back up/up/folder1" failed: No such file or directory (2)
我的第一个版本需要额外的调整来处理空格,因为用[@]扩展数组并通过用()括起扩展来创建一个新数组会导致路径中的空格将路径分解为多个数组元素(见Tonin在下面的回答。)
答案 0 :(得分:4)
在变量中嵌入引号并没有做任何有用的事情。执行此类操作的最佳方法是在展开变量时在变量周围加上双引号,并将数组展开为"${arrayname[@]}"
- 这样bash会将数组的每个元素视为单独的单词,即使它们包含空格或其他shell元字符。棘手的是用$ backuppath为数组的每个元素添加前缀,但是你有正确的方法(除了在它周围加上引号,而不是在值中):
backuppath='/path/with spaces/'
backupitems=('folder 1' 'folder 2') # declare -a is optional
backupitempaths=("${backupitems[@]/#/$backuppath}")
rsync "${backupitempaths[@]}" /path/to/destination
答案 1 :(得分:1)
脚本中的问题在于bash定义数组元素的方式。元素由空格分隔。因此,当您将修改后的数组元素重新分配回数组时,实际上创建的元素实际上比首先要多。您可以通过在数组声明和每个赋值之后添加echo ${#backupitems[@]}
来查看。
最后,当你在$backup
变量中展平数组时,bash甚至会使情况恶化,因为rsync认为它是相对路径。
要解决此问题,我将使用以下脚本,该脚本适用于文件名中的空格(或路径中的任何位置):
backuppath='/path/to/backup/folders/'
declare -a backupitems=('folder 1' 'folder 2')
PIFS=$IFS
# prevents creating new elements from the original array
IFS=''
backupitems=(${backupitems[@]/#/$backuppath})
rsync ${backupitems[@]} /path/to/destination
IFS=$PIFS
脚本重新声明IFS
变量,该变量在创建数组时更改有关记录分隔符的bash行为。但是,与您的脚本略有不同,因为$backup
变量不能再使用,否则您将在实际使用它之前将其展平。我们希望这不是一个要求。
答案 2 :(得分:0)
摆脱这些引用:
backuppath='/path/to/backup/folders/'
declare -a backupitems=('folder1' 'folder2')
backupitems=(${backupitems[@]/#/$backuppath})
backup=${backupitems[@]}
rsync ${backup} /path/to/destination