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