【问题标题】:python subprocess output without \n没有\n的python子进程输出
【发布时间】:2016-07-25 04:05:25
【问题描述】:

这是一个运行子进程的简单脚本,它从终端的ifconfig 命令输出中检索 IP。 我注意到subprocess.check_output() 总是返回一个带有\n 的值。

我希望得到一个返回值没有\n。 如何做到这一点?

$ python
>>> import subprocess
>>> subprocess.check_output("ifconfig en0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True)
'129.194.246.245\n'

【问题讨论】:

  • echo 添加换行符..
  • 不仅如此。如果我在 bash mac OS X 上运行 subprocess.check_output("ifconfig en0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True) 检索我的 IP 地址,则返回行也存在
  • @Jupiter,你也可以很容易地使用 python 解析所有输出
  • 用你的ifconfig | awk | grep -o 命令替换echo 是一个相当大的变化,使很多答案无效。并不是说您的断言因此而更加正确。
  • @Jupiter 看来您是一名 PHP 程序员。请注意,PHP exec 明确(恕我直言)从返回的输出中删除尾随换行符。

标签: python


【解决方案1】:

通用方式:

subprocess.check_output("echo hello world", shell=True).strip()

【讨论】:

  • 这不能回答 why 输出中有换行符;对于echogrep 输出。提示:添加它的不是check_output()
  • 问题不是为什么,而是如何删除它:-DI 猜测答案是命令行二进制文件在其输出的末尾添加了一个新行,以便在之后(在不同的行)。
  • 我认为我们只是对问题的解释不同。 我注意到subprocess.check_output() 总是返回一个带有\n 的值。并且 OP 更改了问题以表明即使使用 grep -o 他们仍然得到那个换行符(好像要证明指向 echo 作为换行符来源的答案是错误的)。
【解决方案2】:

subprocess.check_output() 确实添加换行符。 echo 确实如此。您可以使用-n 开关来禁止换行,但您必须避免使用shell 内置实现(所以使用/bin/echo):

>>> import subprocess
>>> subprocess.check_output('/bin/echo -n hello world', shell=True)
'hello world'

如果您改用echo -n,您可以获得字符串'-n hello world\n',因为并非所有sh 实现都支持-n 开关支持echo(例如OS X)。

当然,您总是可以使用str.rstrip()str.strip() 来删除空格,但不要在这里责备subprocess

>>> subprocess.check_output('echo hello world', shell=True).rstrip('\n')
'hello world'

您的问题更新添加了一个使用awkgrep 的更复杂示例:

subprocess.check_output("ifconfig en0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True)

这里 grep 添加(最终)换行符。 grep -o 可能会打印just匹配的文本,但仍会添加换行符来分隔匹配项。见grep manual

-o
--only-matching

只打印匹配行的匹配(非空)部分,每个这样的部分都在单独的输出行上。

强调我的。

您可以在末尾添加 tr -d '\n' 以从管道输出中删除任何换行符:

>>> subprocess.check_output(
...     "ifconfig en0 | awk '{ print $2}' | "
...     "grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | "
...     "tr -d '\n'", shell=True)
'172.17.174.160'

【讨论】:

  • 我认为这不一定是关于echo的问题,rstrip是OP需要的
  • @PadraicCunningham:这取决于。需要指出的是,check_process 添加这个换行符的假设是不正确的。
  • @PadraicCunningham:考虑到问题的变化,OP 几乎可以肯定仍然声称换行符是由check_output 添加的。您可以使用 str.rstrip() 删除换行符在这里并不重要。
  • @PadraicCunningham 我认为 Martijn 的观点 仍然 是为了证明 subprocess.check_output 根本没有添加 any 换行符,您只能通过以下方式证明管道到一个肯定会删除换行符的命令。赞成。
  • 重要的是要指出为什么某些东西不像 OP 所期望的那样工作。好的答案可以做到这一点,而不是仅仅抛出一个有效但没有参考 OP 原始方法的随机解决方案。我们在这里学习和教授东西,而不是给出每个人都应该不假思索地复制/粘贴的代码。 – 这是一个很好的答案!
【解决方案3】:

您可以str.rstrip 任何换行符或使用 Martijn 建议的内容,也可以使用 python 解析输出,但需要 awkgrep 不会添加任何换行符:

你可以拆分:

out = subprocess.check_output(["ifconfig", "en0"])

for line in out.splitlines():
    if line.lstrip().startswith("inet "):
        print(line.split()[1].split(":", 2)[1])
        print(ip.search(line))
        break

或者使用你自己的正则表达式:

import  re

out = subprocess.check_output(["ifconfig", "en0"])

print(re.search('([0-9]{1,3}[\.]){3}[0-9]{1,3}', out).group())

关键是您不需要 awk 或 grep。

如果您想匹配 ipv4 或 ipv6 并在返回错误时捕获,即没有这样的接口,您可以捕获 CalledProcessError,它将针对任何非零退出状态引发,很容易使用 ipv4 的正则表达式但是对于 ipv6,使用inet6 来获取 ipv6 地址会更简单。

from subprocess import check_output, CalledProcessError
import re

def get_ip(iface, ipv="ipv4"):
    try:
       out = check_output(["ifconfig", iface])
    except CalledProcessError as e:
        print(e.message)
        return False
    try:
        if ipv == "ipv4":
            return re.search('([0-9]{1,3}[\.]){3}[0-9]{1,3}', out).group()
        return re.search("(?<=inet6 addr:)(.*?)(?=/)", out).group().lstrip()
    except AttributeError as e:
        print("No {} address for interface {}".format(ipv, iface))
        return False

演示:

In [2]: get_ip("wlan0")
Out[2]: '192.168.43.168'

In [3]: get_ip("wlan0","ipv6")
Out[3]: 'fe80::120b:a9ff:fe03:bb10'

In [4]: get_ip("wlan1","ipv6")
wlan1: error fetching interface information: Device not found   
Out[4]: False

【讨论】:

  • str.lstrip('addr:')?这将从一开始就删除字符adr:。以任何顺序。如果我有 IPv6 地址怎么办?
  • @MartijnPieters。我,那你找inet6,你也可以在:上拆分一次,有很多选择。
  • 重点是您不应该使用lstrip 删除前缀。
  • @MartijnPieters,您能否解释一下 OP 的正则表达式如何匹配 ipv6 地址?
  • 参见上面的 cmets。不需要重复已经说过的话。 striprstriplstrip 是删除固定前缀和后缀的可怕选择。
【解决方案4】:

这就是你所拥有的:

$ python
>>> import subprocess
>>> subprocess.check_output("ifconfig eth0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True)
'172.31.94.116\n'

试试这个:

$ python
>>> import subprocess
>>> subprocess.check_output("ifconfig eth0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True).strip()
'172.31.94.116'

【讨论】:

    猜你喜欢
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    • 2023-02-04
    • 2020-10-18
    相关资源
    最近更新 更多