for 循环文件夹列表而不扩展

for 循环文件夹列表而不扩展

我尝试在 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

相关内容