我尝试在 bash shell 上为备份脚本生成命令行。
简单的例子:
EXCLUDES="/home/*/.cache/* /var/cache/* /var/tmp/* /var/lib/lxcfs/cgroup/*";
for FOLDER in $EXCLUDES; do printf -- '--exclude %b\n' "$FOLDER" ; done
Run Code Online (Sandbox Code Playgroud)
应该导致:
--exclude '/home/*/.cache/*' --exclude '/var/cache/*' --exclude '/var/tmp/*' --exclude '/var/lib/lxcfs/cgroup/*'
Run Code Online (Sandbox Code Playgroud)
但问题是,文件夹是从 shell 扩展的。我确实尝试了许多带有 echo / printf / quoting / IFS 的示例......但没有正确的结果。
有任何解决这个问题的方法吗?
每当您必须使用文件名全局指定路径名或路径名列表,或者通常只是您打算循环和/或用作某些命令的参数列表的列表时,请使用数组。
如果您不使用数组而是使用字符串,则将无法处理其中包含空格的内容(因为您使用空格作为字符串中的分隔符)。这也使得循环字符串的内容变得困难,因为您将不得不调用分词(通过不引用变量扩展)。但这也会导致文件名通配,除非您使用set -f.
在大多数 shell 中,即使是在 plain 中/bin/sh,也请改用数组。在 中sh,使用位置参数数组 ( $@)。
对于bash,使用带引号的字符串数组,例如
excludes=( '/home/*/.cache/*'
'/var/cache/*'
'/var/tmp/*'
'/var/lib/lxcfs/cgroup/*' )
Run Code Online (Sandbox Code Playgroud)
然后,
rsync_opts=( --verbose --archive )
for excl in "${excludes[@]}"; do
rsync_opts+=( --exclude="$excl" )
done
Run Code Online (Sandbox Code Playgroud)
之后,
rsync "${rsync_opts[@]}" source/ target
Run Code Online (Sandbox Code Playgroud)
请注意,引用在上述所有变量扩展中都很重要。扩展"${array[@]}"(以及"$@"下面的)导致所讨论数组的单独引用元素的列表(但仅当双引号时!)。
对于任何/bin/sh外壳:
set -- '/home/*/.cache/*' \
'/var/cache/*' \
'/var/tmp/*' \
'/var/lib/lxcfs/cgroup/*'
for excl do
set -- "$@" --exclude="$excl"
shift
done
set -- --verbose --archive "$@"
rsync "$@" source/ target
Run Code Online (Sandbox Code Playgroud)