双重逃脱角色

时间:2014-01-24 17:55:17

标签: python regex python-2.7 escaping

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

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和{{ 1}}。

此处参考是字符串经过的完整步骤...

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)

1 个答案:

答案 0 :(得分: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/
    

    其中输入字符串为“1”,预期输出为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. 如果运气好的话,你应该能够将它应用到有问题的表达中。

  6. 使用strong quoting(单引号中的周围命令)可能最简单,它告诉bash不要解释字符串,尽管你可能仍然必须转义括号()

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

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

    所以

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

    给出

    oneone
    

    使用强引号的等价物是:

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