有一个输入参数,其中包含一系列文件(带有通配符或文件夹的文件),如下所示:
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
如果您愿意解析混乱的引号,则输出会显示这一点。)
实际上,使用数组带来的所有好处在此分配中都变得毫无意义。