Bash:将构建的数组作为参数列表运行?

Bash:将构建的数组作为参数列表运行?

我在使用 borgbackup 时遇到了这个问题,但因为反应是相同的,所以我将rsync在我的示例中使用。

我想通过向每个参数添加前缀来构建一个参数数组,然后将该数组赋予rsync.但rsync表现得就像它不存在一样。

使用这个脚本:

#!/usr/bin/env bash
#

declare -a exclude_String
for excludestr in $(cat ./list); do
    exclude_String+=(--exclude=$excludestr)
done
rsync "${exclude_String[@]}" . $Destination

./list

'/home/*'
'*.vim*'

正在运行的进程的Aps确实正确显示了参数:

/usr/bin/rsync --exclude='*.vim*' --exclude='/home/*' . DESTINATION

rsync仍然表现得好像他们不在那里一样。我发现这个问题关于这个主题,所以我尝试:

#!/usr/bin/env bash
#

declare -a exclude_String
exclude_String+=(--exclude='/home/*')
exclude_String+=(--exclude='*.vim*')

rsync "${exclude_String[@]}" . $Destination

这确实有效。

我还不太了解 shell 扩展和其他东西,我试过在各处引用和双引号,只是想看看是否能找到一些东西,但没有运气。

关于如何实现这一目标有什么想法吗?

答案1

如果文件实际上包含'/home/*', 和引号,则引号将出现在excludestr循环中的值中,然后出现在您提供给 的参数中rsync。在这种情况下,它们不是 shell 命令的一部分,只是命令替换的扩展值的一部分。

另一方面,如果你写exclude_String+=(--exclude='/home/*'),现在引号是 shell 命令的一部分,并在该命令的处理过程中被删除。 (具有制作*普通角色的效果。)

rsync实际上并不期望或处理引号作为排除模式的一部分,它只会将它们视为任何其他字符,并且会排除名称包含引号的文件。因此,如果您将排除模式作为某些文件中的数据,则不应在其中包含引号。

for x in $(cat file)另外,请使用来代替while IFS= read -r line; do ...; done < file,或者在本例中使用mapfile -t exclude_String < file。该命令替换cat会调用分词,因此您不能使用包含空格的排除模式。它还立即在循环的单词列表上调用模式的通配for。这不是你想要的。


一般来说,您需要的是:

excludes=()
while IFS= read -r line; do 
    excludes+=(--exclude="$line")
done < ./list 
rsync "$flags" "${excludes[@]}" . "$destination"

仅包含./list要排除的模式:

/home/*
*.vim*

"$line"( in周围的引号+=(--exclude="$line")可防止 shell 通配--exclude=something当前目录中调用的文件。)

尽管在这种情况下rsync,您也可以使用--exclude-from

rsync "$flags" --exclude-from=./list . "$destination"

如果您要使用比文件更复杂的东西来提供循环,您可以使用进程替换:

while IFS= read -r line; do
    excludes+=(--exclude="$line")
done < <(some command that produces the exclude patterns)

也可以看看:为什么我的变量在一个“while read”循环中是本地变量,但在另一个看似相似的循环中却不是?

答案2

正如伊尔卡丘解释的那样,您的问题是单引号不应成为模式的一部分,并且如果您在 shell 上下文中编写模式,shell 将删除它们。

但是,看起来您可以绕过从文件中显式读取模式的过程:

rsync --exclude-from=./list source/ target

使用--exclude-from=FILENAMErsync将从指定的 中读取排除模式FILENAME。请注意,执行此操作时,模式中不应包含单引号。

相关内容