【问题标题】:Doubled escape character双倍转义字符
【发布时间】:2014-02-15 20:01:36
【问题描述】:

我目前正在尝试执行以下操作:

cmd = r'sudo sed -irn "1!N; s/<ip>127.0.0.1<\/ip>(\n.*4000.*)/<ip>0.0.0.0<\/ip>\1/" /usr/something.conf'
subprocess.Popen(cmd)

但是 Popen 抱怨 \\1 是一个无效的引用。在 pdb 中检查后,我看到了这一点,

'sudo sed -irn "1!N; s/<ip>127.0.0.1<\\/ip>(\\n.*4000.*)/<ip>0.0.0.0<\\/ip>\\1/" /usr/something.conf'

似乎 python 正在添加一个额外的\。有什么办法可以防止这种情况发生,以便我可以像使用 Popen 一样运行命令?

另外,为了简单起见,我在示例中省略了它,但这实际上是在传递给 Popen 之前被包装在 SSH 调用中,所以是的......它确实需要使用 Popen 和 sed 来完成。

作为参考,这里是字符串要运行的完整步骤链...

def _formatCmd(cmdString, host=None, user=None, keyfile=None):
    cmd = []
    if host:
        cmd.append('ssh')
        keyfile = keyfile or getKeyFile()
        if keyfile:
            cmd.append('-i')
            cmd.append(keyfile)
        cmd.append("%s@%s" % (user, host))
        cmd.append(cmdString)
    else:
        cmd += cmdString.split()

    return cmd


def runCmd(host, user, cmd, timeout=None, cleanup=False):
    try:
        cmd = _formatCmd(cmd, host=host, user=user)
    except:
        pass

    #create cmd and add it to list of running cmds
    proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
    runningCmds[proc.pid] = proc

    t = threading.Timer(timeout, proc.kill)
    t.start()
    stdout, stderr = proc.communicate()
    t.cancel()

    del runningCmds[proc.pid]
    return (proc.returncode, stdout, stderr)

cmd = r'sudo sed -irn "1!N; s/<ip>127.0.0.1<\/ip>(\n.*4000.*)/<ip>0.0.0.0<\/ip>\1/" /usr/something.conf'
runCmd('1.1.1.1', 'username', cmd)

返回的确切错误信息是:

sed: -e expression #1, char 59: invalid reference \\1 on `s' command's RHS

【问题讨论】:

  • 请注意,r'\1' 与没有r 的'\\1' 相同。它们是编写相同字符串的两种方式。 Python 没有添加额外的反斜杠。您看到的是 pdb 以非原始模式打印字符串。
  • 您能否在不简化的情况下发布完整的代码,以及您看到的 exact 错误消息?当您遇到逃避问题时,所有层都很重要。
  • 您正在转义一个不需要通过使用原始表示法进行转义的字符串 (cmd = r'string')
  • 据我了解,您正在远程机器上使用 SSH 使用 sed 执行此命令。由于您正在远程编辑或写入文件,因此您可以轻松地使用paramiko.SFTPClient。
  • 你为什么用r''?

标签: python regex python-2.7 escaping


【解决方案1】:

问题在于 shell 正在执行自己的解释/转义。我在使用 cygwin 时发现了类似的东西(在 cygwin 的情况下,shell 是 bash)。

你得到错误的事实:

sed: -e expression #1, char 59: invalid reference \\1 on `s' command's RHS

暗示括号() 是问题所在,而不是\1 的转义。本质上,它无法找到该组,因此您需要转义括号\(...\)。

要找到原因,诀窍是使用echo 来调试正在发送的内容:

  1. 将正则表达式简化为一个组和匹配项。类似的东西:

    s/(one)/\1\1/
    

    输入字符串为“one”,预期输出为oneone

  2. 将您的cmd 更改为echo,这样您传递给shell 的是echo s/(one)/\1\1/

  3. 我猜你会看到类似bash: syntax error near unexpected token '(' 的东西。这为我们提供了线索。基本上,我们需要转义括号。

  4. 所以现在试试echo s/\(one\)/\1\1。就我而言,我看到类似

    s/(one)/\1\1
    
  5. 如果运气好的话,您应该能够将其应用于有问题的表达式。

使用strong quoting(用单引号括起来的命令)可能是最简单的,它告诉bash 不要解释字符串,尽管您可能仍然需要转义括号()。

顺便说一句,对于cygwin来说,事情需要被转义两次,所以实际正确的表达式是:

sed s/\\\(one\\\)/\\1\\1/

所以

echo one | sed s/\\\(one\\\)/\\1\\1/

给了

oneone

使用强引用的等价物是:

 echo one | sed 's/\(one\)/\1\1/'

【讨论】:

  • 只缺少转义 () !谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-30
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多