for 循环文件夹列表没有扩展

Tho*_*mas 2 bash 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
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 的示例......但没有正确的结果。

有任何解决这个问题的方法吗?

Kus*_*nda 5

每当您必须使用文件名全局指定路径名或路径名列表,或者通常只是您打算循环和/或用作某些命令的参数列表的列表时,请使用数组。

如果您不使用数组而是使用字符串,则将无法处理其中包含空格的内容(因为您使用空格作为字符串中的分隔符)。这也使得循环字符串的内容变得困难,因为您将不得不调用分词(通过不引用变量扩展)。但这也会导致文件名通配,除非您使用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)