【问题标题】:Bash: Insert escapes to variable containing spacesBash:将转义插入包含空格的变量
【发布时间】:2013-02-25 03:28:41
【问题描述】:

尝试在 bash 中使用 scp 将远程文件复制到我的本地系统
我已经获得了我想要的文件名并分配给变量,$lastModifiedFile
但问题是文件名中包含空格。
要将此变量与 scp 一起使用,需要使用反斜杠对空格进行转义。
有没有一种简单的方法来格式化这个变量并在必要的地方(即空格)插入正确的转义字符?

#!/bin/bash

lastModifiedFile=$(sshpass -p 'passw0rd' ssh user@server 'ls -tr /path/output*| tail -n 1')
echo "$lastModifiedFile"

sshpass -p 'passw0rd' scp user@server:"$lastModifiedFile" /root/

这是脚本输出..

[user@host ~]# ./script.sh 
/path/outputSat Mar 09 151905 GMT 2013.html
scp: /path/outputSat: No such file or directory
scp: Mar: No such file or directory
scp: 09: No such file or directory
scp: 151905: No such file or directory
scp: GMT: No such file or directory
scp: 2013.html: No such file or directory

我正在寻找类似下面的东西,甚至是更简单的解决方案? ..

escapedFilename=""

for letter in $lastModifiedFile
    if $letter == " "
        $escapedFilename += "\ "
    else
        $escapedFilename += $letter

【问题讨论】:

    标签: bash escaping spaces


    【解决方案1】:

    就这样吧:

    sshpass -p 'passw0rd' scp 'user@server:$lastModifiedFile' /root/
    

    【讨论】:

    • 这对我不起作用。即使在控制台中输入我也需要'server:foo\ bar'server:foo\ bar'server:foo bar' 都不够。
    • 这给了我scp /path/outputSun Mar 03 072433 GMT 2013.html,它没有被转义,即使手动也无法工作
    【解决方案2】:

    有点倾斜牙签综合症:

    param=user@server:${lastModifiedFile// /\\ /}

    sshpass -p 'passw0rd' scp "$param" /root/

    编辑:看来scp 不喜欢我。我需要在测试中增加一个额外的变量级别...... :)

    编辑 2: 根据 OP 的反馈,exact 解决方案似乎包括使用 ${lastModifiedFile// /\\ \\} 我只是希望在其他文件名中除了空格之外没有其他字符需要转义:)

    【讨论】:

    • 牙签的输出似乎不正确scp: /path/outputSat /Mar /09 /151905 /GMT /2013.html: No such file or directory .. 这些应该是放在空格前的反斜杠
    • 很奇怪。 A="/tmp/foo bar baz"; B=10.0.1.119:${A// /\\ }; scp "$B" /test 为我工作。可能取决于使用的外壳?
    • 使用 Bash .. 这最终奏效了,${lastModifiedFile// /\\ \\} .. 感谢您的帮助!想要更新你的答案并且不接受?
    【解决方案3】:

    这里有几个方法可以处理文件名中的几乎所有内容(不仅仅是空格)。首先,bash 的 printf 内置有一个 %q 格式,可以在字符串中添加引号/转义/任何内容:

    sshpass -p 'passw0rd' scp user@server:"$(printf %q "$lastModifiedFile")" /root/
    

    但是请注意,这引用/转义/等它适合由 bash 解释。如果远程计算机的默认 shell 是其他东西,这可能并非在所有情况下都有效。

    选项二在原则上更简单(但在实践中有点混乱),并且应该与更远程的 shell 兼容。在这里,我将文件名括在单引号中,这应该适用于文件名中的单引号以外的任何内容。对于那些,我替换'\''(它结束单引号字符串,添加转义单引号,然后重新启动单引号字符串):

    repl="'\''" # Have to store this in a variable to work around a bash parsing oddity
    sshpass -p 'passw0rd' scp user@server:"'${lastModifiedFile//\'/$repl}'" /root/
    

    【讨论】:

      【解决方案4】:

      在传递给远程系统的文件名周围使用单引号,这样它就不会被分词。

      lastModifiedFile=$(sshpass -p 'passw0rd' ssh user@server 'ls -tr /path/output*| tail -n 1')
      echo "$lastModifiedFile"
      
      sshpass -p 'passw0rd' scp user@server:"'$lastModifiedFile'" /root/
      

      sshpass -p 'passw0rd' scp "user@server:'$lastModifiedFile'" /root/
      

      【讨论】:

        猜你喜欢
        • 2013-11-15
        • 1970-01-01
        • 2019-03-23
        • 1970-01-01
        • 2019-04-05
        • 2021-03-20
        • 1970-01-01
        • 2013-10-07
        • 2021-07-13
        相关资源
        最近更新 更多