【问题标题】:Copying files via scp, from variable, with double quoted names通过 scp 从变量复制文件,带有双引号
【发布时间】:2014-11-13 21:26:01
【问题描述】:

我正在尝试通过带有 scp 的 ssh 将我的项目从我的机器部署到我的测试服务器。我的问题是,在我部署当前目录中的所有内容之前,我必须跳过一些文件和目录。我的解决方案是,首先检查文件或目录是否符合某些条件,将其名称添加到变量中,当我的循环完成时,它将通过 scp 复制所有内容。然后,我还不明白的另一个问题是 scp 不想复制文件,如果它在变量中用双引号“my-file”括起来。但我可能有名称中带有空格的文件。从命令行可以,但不是来自变量。

我的代码是

#...
FILES_TO_SEND=""
for file in *
do
    if test -d $file
    then
        if ! test $file = "nbproject"
        then
            FILES_TO_SEND="$FILES_TO_SEND \"$file\"" #or with this '$file'
        fi
    fi

    if test -f $file
    then
        if ! test $file = "changelog.html"
        then
            FILES_TO_SEND="$FILES_TO_SEND \"$file\"" #or with this '$file'
        fi
    fi
done

#--- Sending files ---#
scp -r ${FILES_TO_SEND} "${DEPLOY_SERVER}:${DEPLOY_TEST_ENV}"
#...

作为回应

"file1.html": No such file or directory
"file2.c": No such file or directory
"file3.sh": No such file or directory
...

PS:我想提高效率,只需要在 scp 调用上建立 1 个连接。服务器很忙,我不想打开和关闭多次调用它的 scp 连接。

PS2:我无法安装 rsync 或类似的东西。我也不想每次部署时都通过 sftp 手动完成。

【问题讨论】:

    标签: bash scp


    【解决方案1】:

    bash(或任何其他具有类似支持的shell)中正确(且更简单)的方法是使用数组而不是字符串来保存文件名。

    #...
    declare -a FILES_TO_SEND
    for file in *; do
        if [[ -d $file ]]; then
            if ! [[ $file = "nbproject" ]]; then
                FILES_TO_SEND+=( "$file" )
            fi
        elif [[ -f $file ]]; then
            if ! [[ $file = "changelog.html" ]]; then
                FILES_TO_SEND+=( "$file" )
            fi
        fi
    done
    
    #--- Sending files ---#
    scp -r "${FILES_TO_SEND[@]}" "${DEPLOY_SERVER}:${DEPLOY_TEST_ENV}"
    #...
    

    甚至更简单:跳过显式的gather-files-in-a-loop方法,并使用匹配除禁止文件名和目录名之外的所有内容的模式。

    shopt -s extglob
    scp -r !(changelog.html|nbproject) "{$DEPLOY_SERVER}:${DEPLOY_TEST_ENV}"
    

    【讨论】:

    • 你能解释一下 shopt -s extglob 到底是做什么的吗?
    • 为什么数组在第一种情况下更好?
    • 将数组视为额外的引用级别,当它需要自己引用时效果更好。通常,参数值中嵌入的引号不能在参数展开后引用空格。 shopt -s extglob!(...) 模式所必需的,它匹配除了括号内的所有内容。
    • 我最喜欢这个解决方案,我在这里找到了关于 extglob 的解释 aplawrence.com/Words2005/2005_05_25.html
    • FILES_TO_SEND 被扩展,但值中包含的任何引号都被视为文字字符,而不是需要删除引号的运算符。 name="\"foo bar\""; ls $name 等价于ls \"foo bar\",而不是ls "foo bar"
    【解决方案2】:

    您可以这样做来生成“有效”代码:

    FILES_TO_SEND=$(printf '%s "%q"' "$FILES_TO_SEND" "$file")
    

    %q 将完成引用字符的工作,例如空格、" 等。

    例如:

    $ printf '"%q"\n' 'Foo"Ba    '
    "Foo\"Ba\ \ \ \ "
    

    或者你可以试试xargs:

    find '(' -type f -not -name 'changelog.html' ')' -or '(' -type d -not -path '*/nbproject/*' ')' -print0 | xargs -r0 scp -r "${DEPLOY_SERVER}:${DEPLOY_TEST_ENV}"
    

    xargs 在你的情况下会很好,但我找不到方法告诉 scp "${DEPLOY_SERVER}:${DEPLOY_TEST_ENV}" 是目标而不是源。

    【讨论】:

    • 有趣。我会尽快尝试您的建议,并会对此提供反馈。 10x
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多