使用变量通过 rsync 排除多个目录

使用变量通过 rsync 排除多个目录

以下代码片段是我正在处理的一个更大的 Bash 脚本的一部分。我的目的是将输入变量作为参数传递给 Rsync。

我设法使其大部分工作,除了“--exclude”参数的参数:

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"  

rsync ${DRYRUNARG} -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    --exclude={/VirtualBox_VMs/*/Snapshots,/snap,/Downloads,/.*} \                                  
    ${MNTPNT}${DEST_DIR}

该代码非常适合我的需要,但我仍然希望看到那些必须由变量定义的排除目录。

我需要的结果代码应该是这样的:

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"
EXCLUDE="/VirtualBox_VMs/*/Snapshots,/snap,/Downloads,/.*"       

rsync ${DRYRUNARG} -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    --exclude=${EXCLUDE} \                                  
    ${MNTPNT}${DEST_DIR}

上面的代码不起作用。该命令执行时没有错误,但无法排除任何内容。有趣的是,如果我只用一个目录定义 EXCLUDE 变量,它确实可以工作,即使它遵循用于 INCLUDE 变量的相同结构。

我确信我犯了一些愚蠢的错误。它可能在哪里?

答案1

不要将单独条目的列表降级为单个字符串。这使得解析不同的条目变得困难,并且您必须处理可能包含用作分隔符的字符等的条目的问题。此外,rsync不知道如何解析包含/排除模式的逗号分隔列表。

相反,使用数组:

#!/bin/bash

INCLUDE=( '/.vim*' '/.git*' /.ssh .bash_aliases .bashrc )
EXCLUDE=( '/VirtualBox_VMs/*/Snapshots'  /snap /Downloads '/.*' )

然后在这些列表中的每个项目前面插入--exclude和,创建新列表:--include

exclude_opts=()
for item in "${EXCLUDE[@]}"; do
    exclude_opts+=( --exclude="$item" )
done

include_opts=()
for item in "${INCLUDE[@]}"; do
    include_opts+=( --include="$item" )
done

然后只需在调用中使用这些新列表rsync(假设这SOURCE_DIRS是一些源目录数组):

rsync ${DRYRUNARG:+"$DRYRUNARG"} -avzhP --delete \
    "${include_opts[@]}" \
    "${exclude_opts[@]}" \
    "${SOURCE_DIRS[@]}" \
    "$MNTPNT/$DEST_DIR"

在这里,$DRYRUNARG如果已设置且不为空,则将使用引号引起来,否则它根本不会成为命令行的一部分。

答案2

一种方法是使用变量作为文件输入,例如--exclude-from

EXCLUDE_DIRS="VirtualBox_VMs
Downloads
Snapshots"

rsync  -arv --exclude-from=<(printf "%s" "$EXCLUDE_DIRS";)  $SOURCE $DESTINATION

答案3

我也一直在尝试同样的事情。并且发现这个问题令人困惑。

我能做的最好的事情就是(使用/bin/bash)将逗号分隔列表转换为分隔列表--exclude

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"
EPATHS=("/VirtualBox_VMs/*/Snapshots" "/snap" "/Downloads" "/.*")     

for path in "${EPATHS[@]}"; do
   EXCLUDE="$EXCLUDE --exclude=$path"
done

rsync -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    $EXCLUDE             \                                  
    ${MNTPNT} ${DEST_DIR}

这是一个不完整且不优雅的解决方案,但它有效。

挥之不去的问题是我无法让它与路径名中的空格一起使用。当我尝试在串联中添加引号时,例如

EXCLUDE="$EXCLUDE --exclude=\"$path\""

bash似乎用更多的单引号把它粘住了。

如前所述,set -x这是我的朋友。

相关内容