Rsync脚本中传递exclude变量参数时忽略双引号引发路径错误及异常包含主目录问题
我遇到过类似的问题,这本质上是bash中参数拆分逻辑导致的,咱们一步步拆解问题并解决:
问题根源分析
你现在把exclude_list用双引号包裹后传递给rsync,bash会把整个字符串当作单个完整参数传给rsync。但rsync的逻辑是:--exclude=xxx是独立的命令选项,不是要同步的源路径。所以rsync会误把--exclude=lost+found当成了源路径的一部分,加上脚本执行时的工作目录是用户主目录,就出现了找不到/home/user/ --exclude=lost+found的错误。
至于为什么echo rsync ...看起来正常?因为echo只是把字符串按原样输出,不会像实际执行命令那样做参数拆分,视觉上是正确的,但实际参数传递逻辑完全不同。
解决方案
方案1:用数组存储exclude参数(推荐,安全可靠)
这是bash脚本处理多参数场景的标准做法,数组可以保留每个--exclude=xxx的独立性,让rsync正确识别为命令选项。
修改你的脚本如下:
#!/bin/bash # List of source folders SRC_FOLDERS=( [0]="/mnt/load-1/" [1]="/mnt/load-2/" ) # List of backup folders DEST_FOLDERS=( [0]="/mnt/load-1-b/" [1]="/mnt/load-2-b/" ) # List of folders to exclude during backup EXCLUDE_FOLDERS=( "lost+found" "lost-found" ) # 初始化数组(替代原有的字符串变量) exclude_list=() # 循环往数组中添加每个exclude选项 for exclude_folder in "${EXCLUDE_FOLDERS[@]}"; do exclude_list+=( "--exclude=$exclude_folder" ) done # Loop through each folder pair for i in "${!SRC_FOLDERS[@]}"; do src=${SRC_FOLDERS[$i]} dest=${DEST_FOLDERS[$i]} # 用数组展开语法传递参数,每个元素都是独立的命令选项 rsync -av --dry-run "${exclude_list[@]}" "$src" "$dest" done
关键说明:
"${exclude_list[@]}"在双引号包裹下,会把数组的每个元素拆分成单独的参数,正好匹配rsync对--exclude选项的要求。这种方法还能兼容文件夹名含空格、特殊字符的场景,安全性拉满。
方案2:使用eval(不推荐,仅作应急参考)
如果因为特殊原因必须用字符串存储exclude参数,可以用eval强制bash重新解析参数,但存在安全风险:如果EXCLUDE_FOLDERS里包含恶意字符(比如; rm -rf /),eval会执行后续的危险命令,所以绝不推荐在生产环境使用。
修改rsync执行行如下:
eval rsync -av --dry-run "$exclude_list" "$src" "$dest"
验证效果
修改后再运行脚本,rsync会正确识别每个--exclude选项,不会再把它们误判为源路径,也就不会出现找不到主目录下奇怪路径的错误了。
备注:内容来源于stack exchange,提问作者lz_linux

