我正在尝试从我的Python(版本2.6.5)代码中运行一个shell命令,但它生成的输出不同于在shell中运行的相同命令(bash):
击:
~> ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//'
192.168.1.10
的Python:
>>> def get_ip():
... cmd_string = "ifconfig eth0 | sed -rn \'s/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//\'"
... process = subprocess.Popen(cmd_string, shell=True, stdout=subprocess.PIPE)
... out, err = process.communicate()
... return out
...
>>> get_ip()
'\x01\n'
我的猜测是,我需要在python中运行时以某种方式转义引号,但我不知道该怎么做。
注意:我无法在需要运行此代码的计算机上安装其他模块或更新python。它需要与Python 2.6.5和标准库一样工作。
答案 0 :(得分:1)
您的代码无效的原因是您没有足够的逃避。你逃脱了引号,但没有其他东西需要转义。
让我们看看你想要的命令行:
ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//'
打印出您的实际命令行(仅print cmd_string
)
ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*//p' | sed 's/^[ ]*//;s/[ ]*$//'
显然这些都不一样。关键的区别在于你的\1
已被一个不可见的控制字符替换,即ord为1的那个(即ctrl-A)。 (你还用标签字符替换了每个\t
,但那个可能不会破坏任何东西。)
打印出repr
行(print repr(cmd_string)
)通常也有帮助:
"ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\\.){3}[0-9]{1,3}).*/\x01/p' | sed 's/^[ \t]*//;s/[ \t]*$//'"
\x01
应该立即提醒您正在进行的操作 - 或者,即使您不理解它,它也会提醒您 某些地方是什么出错了,所以你可以在SO上做一个更简单的搜索或写一个更简单的问题。
你应该养成这样做的习惯,只要你在逃避时出错了。
然而,通常,答案很简单:不要试图找出需要转义的内容和内容,而只需使用原始字符串:
cmd_string = r"ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//'"
现在,当你打印出来时,你会得到:
ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//'
正是你想要的。
答案 1 :(得分:0)
在python中如果你在字符串周围使用双引号,那么你可以在该字符串中使用单引号而不需要转义,反之亦然。但是,反斜杠需要使用额外的\前缀进行转义。
调试时最好的选择可能是添加:
print cmd_string
在设置cmd_string之后,然后将其与原始版本进行比较,以查看是否还缺少其他字符(这些字符也需要转义)。
答案 2 :(得分:0)
你能负担得起安装sh模块吗?
>>> import re, sh
>>> get_ip = lambda: re.search(r'inet addr:(\S+)',
str(sh.ifconfig('eth0'))).group(1)
>>> get_ip()
'10.0.0.202'
清洁版:
def get_ip(interface):
ifconfig = sh.ifconfig(interface)
match = re.search(r'inet addr:(\S+)', str(ifconfig))
if match:
return match.group(1)
return None
>>> get_ip(eth0)
'192.168.1.10'
即使使用子进程,摆脱sed并使用re模块,它也会更简单,并且可以避免一些麻烦。