bash 中仅一个变量中的参数列表

bash 中仅一个变量中的参数列表

有一个输入参数,其中包含一系列文件(带有通配符或文件夹的文件),如下所示:

list="file1 dir1 **.data **.source"

现在这个列表的每个元素都必须以 为前缀--filter=+,将其变成命令参数列表rsync,如下所示:

args='--filter=="+ file1" --filter="+ dir1" --filter="+ **.data" --filter="+ **.source"'

所以,当经过$参数它应该rsync $args正确接收每个参数,其中“+”中的空格必须只是参数的一个字符,而不是两个参数的分隔符。

如何仅使用内置 shell 命令在 shell 脚本 (bash) 中执行此操作?请注意,该rsync命令必须正确接收每个参数。

一次不成功的尝试:

#!/bin/bash
set -f
list="file1 dir1 **.data **.source"
ct=0
arr=""
for i in $list; do
    ct=$(( ct + 1 ))
    arr[$ct]="--filter='+ $i'"
done
args=${arr[*]}

set -x
echo args:$args
rsync $args srcdir destdir
set +x

当它运行时(假设该文件夹srcdir存在于当前目录中),它显示:

$ ./test
+ echo args: '--filter='\''+' 'file1'\''' '--filter='\''+' 'dir1'\''' '--filter='\''+' '**.data'\''' '--filter='\''+' '**.source'\'''
args: --filter='+ file1' --filter='+ dir1' --filter='+ **.data' --filter='+ **.source'
+ rsync '--filter='\''+' 'file1'\''' '--filter='\''+' 'dir1'\''' '--filter='\''+' '**.data'\''' '--filter='\''+' '**.source'\''' a b
Unknown filter rule: `'+'
rsync error: syntax or usage error (code 1) at exclude.c(904) [client=3.1.1]
+ set +x

看看虽然echo正确地显示了每个参数:

args: --filter='+ file1' --filter='+ dir1' --filter='+ **.data' --filter='+ **.source'

rsync命令看起来没有正确理解每个参数,因为“+”完成了参数,而空格不是参数的一部分,而是分隔符,从而破坏了所有参数。

答案1

您可以将其作为一个数组来开始,而不是将文件名和模式列表作为单个字符串:

list=(file1 dir1 "**.data" "**.source")

然后循环遍历元素:

args=()
for item in "${list[@]}" ; do
    args+=(--filter="+ $item")
done

这将创建类似 的参数--filter=+ file1,参数字符串内不带任何引号。 (您不希望引号转到rsync。它会抱怨包含它们的过滤规则,例如rsync "--filter='+ foo'" ...

当您将数组传递给命令时,请确保使用将"${args[@]}"数组元素作为不同的字符串传递:

rsync "${args[@]}" "$srcdir" "$destdir"

相反"--filter=+ foo",我认为你可以使用--include=foo.这将从参数中删除一个有问题的空格(但不会删除文件名模式中的空格或通配符)。


在你的情况下,你曾经set -f禁用通配符,for i in $list应该可以工作,但由于你需要一个数组,所以你最好一开始就使用一个数组。

更重要的是,赋值将数组args=${arr[*]}展平为单个字符串。现在参数内部的空格和参数之间的空格是相等的,--filter=+ file1 --filter=+ dir1 ...shell 无法区分不同类型的空格。不带引号的扩展$args将在任何和所有空白处拆分(set -x如果您愿意解析混乱的引号,则输出会显示这一点。)

实际上,使用数组带来的所有好处在此分配中都变得毫无意义。

相关内容