我目前正在尝试执行以下操作:
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)
答案 0 :(得分:1)
问题是shell正在进行自己的解释/转义。我在使用cygwin时发现了类似的东西(在cygwin案例中,shell是bash)。
您收到错误的事实:
sed: -e expression #1, char 59: invalid reference \\1 on `s' command's RHS
意味着括号()
是问题,而不是\1
的转义。基本上,它无法找到该组,因此您需要转义括号\(...\)
。
要找到原因,诀窍是使用echo
来调试发送的内容:
将正则表达式简化为一个组和匹配。类似的东西:
s/(one)/\1\1/
其中输入字符串为“1”,预期输出为oneone
将您的cmd
更改为echo
,以便传递给shell的内容为echo s/(one)/\1\1/
我猜您会看到类似bash: syntax error near unexpected token '('
的内容。这给了我们线索。基本上,我们需要摆脱括号。
现在尝试echo s/\(one\)/\1\1
。就我而言,我看到像
s/(one)/\1\1
如果运气好的话,你应该能够将它应用到有问题的表达中。
使用strong quoting(单引号中的周围命令)可能最简单,它告诉bash不要解释字符串,尽管你可能仍然必须转义括号()
。
顺便说一下,对于cygwin,事情需要两次转义,所以实际的正确表达是:
sed s/\\\(one\\\)/\\1\\1/
所以
echo one | sed s/\\\(one\\\)/\\1\\1/
给出
oneone
使用强引号的等价物是:
echo one | sed 's/\(one\)/\1\1/'