Bash: 需要帮助将变量传递给 rsync

Bash: need help passing a a variable to rsync

我想将 $home 作为要在 运行 rsync 时排除的目录列表传递。文件:

cat backup_system.sh
#!/bin/bash
set -x
home=''
home=$home'"/home/ravas/Documents/*"',
home=$home'"/home/ravas/Downloads/*"',
home=$home'"/home/ravas/pCloudDrive/*"',
home=$home'"/home/ravas/pCloudLocal/*"',
home=$home'"/home/ravas.old/*"'
echo $home
sudo rsync -aAXv / --exclude={$home,"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} /run/media/ravas/system_backup

备份在没有 $home 变量的情况下运行良好,但如果我添加它,它没有任何效果。

输出的最后两行显示 $home 中列出的目录未使用 --exclude 展开,而其他人是。

不用说,我不太擅长 bash,如有任何帮助,我们将不胜感激!

./backup_system.sh 
+ home=
+ home='"/home/ravas/Documents/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"'
+ echo '"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"'
"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"
+ sudo rsync -aAXv / 
'--exclude="/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"' 
'--exclude=/dev/*' '--exclude=/proc/*' '--exclude=/sys/*' '--exclude=/tmp/*' '--exclude=/run/*' '--exclude=/mnt/*' '--exclude=/media/*' --exclude=/lost+found** /run/media/ravas/system_backup

几乎所有与多参数相关的问题的解决方案都是使用数组:

exclusions=(
  --exclude "/home/ravas/Documents/*"
  --exclude "/home/ravas/Downloads/*"
  --exclude "/home/ravas/pCloudDrive/*"
  --exclude "/home/ravas/pCloudLocal/*"
  --exclude "/home/ravas.old/*"
  --exclude "/dev/*"
  --exclude "/proc/*"
  --exclude "/sys/*"
  --exclude "/tmp/*"
  --exclude "/run/*" 
  --exclude "/mnt/*"
  --exclude "/media/*"
  --exclude "/lost+found"
)

sudo rsync -aAXv / "${exclusions[@]}" /run/media/ravas/system_backup

如果您没有将标准输入用于任何其他用途,您可以使用带有此处文档的 --exclude-from 选项来稍微缩短此时间:

sudo rsync -aAXv / --exclude-from - /run/media/ravas/system_backup <<EOF
/home/ravas/Documents/*
/home/ravas/Downloads/*
/home/ravas/pCloudDrive/*
/home/ravas/pCloudLocal/*
/home/ravas.old/*
/dev/*
/proc/*
/sys/*
/tmp/*
/run/* 
/mnt/*
/media/*
/lost+found
EOF

基本问题是 bash 在您的命令中解析各种内容的顺序对于您要执行的操作来说都是错误的。具体来说,它解析(并应用和删除)引号和转义符,然后扩展 {this,that,theother} 列表,然后扩展变量引用(如 $home)。最终结果是,当 $home 扩展为以逗号分隔的引用元素列表时,引号或逗号无法发挥其预期效果为时已晚。

像往常一样,在这种情况下,数组是处理此问题的最佳方式:

homearray=()
homearray+=("/home/ravas/Documents/*")
homearray+=("/home/ravas/Downloads/*")
homearray+=("/home/ravas/pCloudDrive/*")
homearray+=("/home/ravas/pCloudLocal/*")
homearray+=("/home/ravas.old/*")
# Alternate short form:
# homearray=(/home/ravas/{Documents,Downloads,pCloudDrive,pCloudLocal}/"*" "/home/ravas.old/*")
sudo rsync -aAXv / "${homearray[@]/#/--exclude=}" --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} /run/media/ravas/system_backup

解释:"${homearray[@]/#/--exclude=}" 做了三件事;首先,[@] 使其扩展到数组的所有元素;然后 /#/--exclude= "replaces" 每个元素的开头带有“--exclude=”(本质上,它在每个元素前面加上“--exclude=”),最后它周围的双引号保持通配符 ("*") 防止扩展和破坏。

Bash 中的字符串处理很少是直截了当的,但这里有一些有用的东西...

( list=abc,'"def\ ghi"',jkl ; eval echo --exclude={$list} )

输出:

--exclude=abc --exclude=def\ ghi --exclude=jkl

eval command in Bash and its typical uses