rsync 传递多个从 $@ 排除的内容

Ban*_*tin 1 bash rsync

我正在尝试围绕 rsync 命令制作一个包装器以重用代码。我需要传递源文件夹、目标文件夹,然后传递任意数量的排除目录。这是我的日志;基本上我正在构建我的多个 rsync --从我的“vararg”参数中排除参数。可能有更好的方法,但我发现一个就足够了。

function run_backup(){
    source="$1"
    target="/backups/unraid$2"
    #Copying $source into remote folder $target

    # Building my exclude params
    if [ $# -ge 3 ]; then
        excludes="--exclude '$3'"
        while shift && [ -n "$3" ]; do
            echo $excludes
            excludes="${excludes} --exclude '$3'"
        done
    else
        excludes = "--exclude '/tmp'" # Dummy exclude; I'll handle this case later
    fi
    echo $excludes
    
    # Creating folder because rsync crash otherwise n some case
    ssh -p 22 -i /home/backup/.ssh/mykey unraid@94.23.49.55 "mkdir -p $target"

    # Executing the copy
    set -e
    sudo rsync -azvh \
        -e "ssh  -p 22-i /home/backup/.ssh/mykey "\
        --progress \
        --delete \
        $excludes \
        $source \
        unraid@69.69.69.69:$target
}


mkdir -p /tmp/dummy
echo "dummy" > /tmp/dummy/save-ignored-1
echo "dummy" > /tmp/dummy/save-ignored-2
echo "dummy" > /tmp/dummy/save-test
run_backup /tmp/dummy/ /dummy /tmp/dummy/save-ignored-1 /tmp/dummy/save-ignored-2 /tmp/toto /tmp/tata /tmp/tutu #TODO
Run Code Online (Sandbox Code Playgroud)
--exclude '/tmp/dummy/save-ignored-1'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto' --exclude '/tmp/tata'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto' --exclude '/tmp/tata' --exclude '/tmp/tutu'
++ ssh -p 22-i /home/backup/.ssh/mykey unraid@69.69.69.69 'mkdir -p /backups/unraid/dummy'
++ sudo rsync -azvh -e 'ssh  -p 22 -i /home/backup/.ssh/mykey' --progress --delete --exclude ''\''/tmp/dummy/save-ignored-1'\''' --exclude ''\''/tmp/dummy/save-ignored-2'\''' --exclude ''\''/tmp/toto'\''' --exclude ''\''/tmp/tata'\''' --exclude ''\''/tmp/tutu'\''' /tmp/dummy/ unraid@94.23.49.55:/backups/unraid/dummy
Run Code Online (Sandbox Code Playgroud)

我们可以看到$excludesvar 正是我想要的;但是当我将它传递给 rsync 时,bash 正在对它施展一些魔法。我不知道如何避免这种情况。我想这与扩展有关,但我找不到与我的或相关文档类似的问题。

编辑:第一个答案后的代码:

--exclude '/tmp/dummy/save-ignored-1'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto' --exclude '/tmp/tata'
--exclude '/tmp/dummy/save-ignored-1' --exclude '/tmp/dummy/save-ignored-2' --exclude '/tmp/toto' --exclude '/tmp/tata' --exclude '/tmp/tutu'
++ ssh -p 22-i /home/backup/.ssh/mykey unraid@69.69.69.69 'mkdir -p /backups/unraid/dummy'
++ sudo rsync -azvh -e 'ssh  -p 22 -i /home/backup/.ssh/mykey' --progress --delete --exclude ''\''/tmp/dummy/save-ignored-1'\''' --exclude ''\''/tmp/dummy/save-ignored-2'\''' --exclude ''\''/tmp/toto'\''' --exclude ''\''/tmp/tata'\''' --exclude ''\''/tmp/tutu'\''' /tmp/dummy/ unraid@94.23.49.55:/backups/unraid/dummy
Run Code Online (Sandbox Code Playgroud)

但它不适用于包含引号的字符串(至少是简单的引号)

/tmp/dummy/save-ignored
/tmp/dummy/save non'standard ignored
/tmp/toto
/tmp/tata
/tmp/tutu
++ echo --exclude /tmp/dummy/save-ignored --exclude /tmp/dummy/save 'non'\''standard' ignored --exclude /tmp/toto --exclude /tmp/tata --exclude /tmp/tutu
--exclude /tmp/dummy/save-ignored --exclude /tmp/dummy/save non'standard ignored --exclude /tmp/toto --exclude /tmp/tata --exclude /tmp/tutu
Run Code Online (Sandbox Code Playgroud)

编辑2:没用;只是将其保留为历史 具有所有引用可能性的测试:

function run_backup(){
    excludes=()
    if [ $# -ge 3 ]; then
        echo $3
        excludes+=(--exclude $3)
        while shift && [ -n "$3" ]; do
            echo $3
            excludes+=(--exclude $3)
        done
    else
        excludes+=(--exclude /tmp)
    fi
    set -x
    echo "${excludes[@]}"
}
run_backup /tmp/dummy/ /dummy "/tmp/dummy/save-ignored" "/tmp/dummy/save non'standard ignored" /tmp/toto /tmp/tata /tmp/tutu
Run Code Online (Sandbox Code Playgroud)
++ echo --exclude /tmp/dummy/save 'non'\''standard' --exclude /tmp/toto
--exclude /tmp/dummy/save non'standard --exclude /tmp/toto
++ echo --exclude '/tmp/dummy/save non'\''standard' --exclude /tmp/toto
--exclude /tmp/dummy/save non'standard --exclude /tmp/toto
++ echo --exclude '"/tmp/dummy/save non'\''standard"' --exclude '"/tmp/toto"'
--exclude "/tmp/dummy/save non'standard" --exclude "/tmp/toto"
++ sudo rsync -azvh --dry-run --exclude /tmp/dummy/save 'non'\''standard' --exclude /tmp/toto --dry-run --exclude '/tmp/dummy/save non'\''standard' --exclude /tmp/toto --dry-run --exclude '"/tmp/dummy/save non'\''standard"' --exclude '"/tmp/toto"' --dry-run --exclude /tmp/dummy/save 'non'\''standard' --exclude /tmp/toto --dry-run --exclude /tmp/dummy/save 'non'\''standard' --exclude /tmp/toto --dry-run --exclude '"/tmp/dummy/save' 'non'\''standard"' --exclude '"/tmp/toto"' /tmp unraid@69.69.69.69:/tmp
Run Code Online (Sandbox Code Playgroud)

我的测试的屏幕截图,具有更好的格式输出:我的测试的屏幕截图,具有更好的格式输出

lak*_*tak 5

使用数组而不是字符串。

例如:

opt=()
opt+=(--exclude "first")
opt+=(--exclude "another one")

set -x
echo "${opt[@]}"
Run Code Online (Sandbox Code Playgroud)

这将正确处理空格(输出):

+ echo --exclude first --exclude 'another one'
Run Code Online (Sandbox Code Playgroud)