我在使用 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)
答案2
正如伊尔卡丘解释的那样,您的问题是单引号不应成为模式的一部分,并且如果您在 shell 上下文中编写模式,shell 将删除它们。
但是,看起来您可以绕过从文件中显式读取模式的过程:
rsync --exclude-from=./list source/ target
使用--exclude-from=FILENAME
,rsync
将从指定的 中读取排除模式FILENAME
。请注意,执行此操作时,模式中不应包含单引号。