0

我正在尝试从我的 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 和标准库一起工作。

4

3 回答 3

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]*$//'

正是你想要的。

于 2013-06-24T22:16:59.643 回答
0

在python中,如果您在字符串周围使用双引号,那么您可以在该字符串中使用单引号而无需转义,反之亦然。但是,反斜杠需要使用额外的 \ 前缀进行转义。

可能您最好的调试方法是添加:

print cmd_string

就在设置 cmd_string 之后,然后比较原始版本以查看是否缺少任何其他字符(这些也需要转义)。

于 2013-06-24T21:55:31.807 回答
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 模块,阅读起来会更简单,也省去了一些转义的麻烦。

于 2013-06-24T22:04:40.427 回答