【问题标题】:Executing awk in Python shell在 Python shell 中执行 awk
【发布时间】:2019-05-07 12:41:57
【问题描述】:

我有一个shell 命令,它解析特定内容并提供所需的输出。我需要在 python 中实现这个,但是 shell 命令有一个换行符"\n",当通过 python 命令运行时它不会被执行。

在输出日志中的许多行中,所需的行看起来像 - configurationFile=/app/log/conf/the_jvm_name.4021.logback.xml

我只需要上面的 the_jvm_name。语法将始终相同。 shell 命令工作正常。

Shell 命令 -

ps -ef | grep 12345 | tr " " "\n" | grep logback.configurationFile | awk -F"/" '{print $NF}'| cut -d. -f1

Python(转义所有必需的双引号) -

import subprocess
pid_arr = "12345"
sh_command = "ps -ef | grep "+pid_arr+" | tr \" \" \"\n\" | grep configurationFile | awk -F \"/\" '{print $NF}' | cut -d. -f1"
outpt = subprocess.Popen(sh_command , shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip()

使用 python,我没有得到想要的输出。它只是打印命令中的配置文件。 我在这里想念什么。还有其他更好的方法来获取这些详细信息吗?

【问题讨论】:

  • 最简单的方法是使用python分割和解析subprocess的输出,而不是依赖grep + tr + grep + awk
  • 我已经尝试过了,但它会中断输出。我们可以使用正则表达式吗?

标签: python shell subprocess


【解决方案1】:

您可以在 Python 中使用正则表达式替换来实现您想要的:

output = subprocess.check_output(["ps", "-ef"])
for line in output.splitlines():
  if re.search("12345", line):
    output = re.sub(r".*configurationFile=.*/([^.]+).*", r"\1", line)

这会捕获配置文件路径中最后一个/ 之后的部分,直到下一个.

您可以通过仅检查 12345 的第二列(PID)来使其更加健壮,或者通过在空白处分割每一行:

cols = re.split("\s+", line) 
if len(cols) > 1 and cols[1] == "12345":

或使用更好的正则表达式,例如:

if re.match(r"\S+\s+12345\s", line):

请注意,您也可以通过执行以下操作来显着缩短管道:

ps -ef | sed -nE '/12345/ { s/.*configurationFile=.*\/([^.]*).*/\1/; p }'

【讨论】:

  • Tom,数字 12345 是动态的,它会根据我从其他命令获得的输出不断变化。这是一个进程ID。我会检查这个。 tq!
  • @sdgd 在这种情况下,您可以动态构建正则表达式,或者只是使用将行拆分为列并直接比较(我更新了答案)。
【解决方案2】:

您的 shell 命令有效,但它必须处理太多的输出行和每行太多的字段。一个更简单的解决方案是告诉 ps 命令只给你 1 行,在该行上,只有一个你关心的字段。例如,在我的系统上:

ps -o cmd h 979

将输出:

/usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3

-o cmd 标志将只输出输出的 CMD 列,而h 参数表示告诉ps 省略标题的命令。最后,979 是进程 ID,它告诉 ps 只为该进程输出信息。

此输出与您的问题不完全一样,但足够相似。一旦我们限制了输出,我们就不再需要其他命令了,例如grepawk、...此时,我们可以使用正则表达式来提取我们想要的内容:

from __future__ import print_function
import re
import subprocess

pid = '979'
command = ['ps', '-o', 'cmd', 'h', pid]
output = subprocess.check_output(command)

pattern = re.compile(r"""
    config-file=  # Literal string search
    .+\/          # Everything up to the last forward slash
    ([^.]+)       # Non-dot chars, this is what we want
""", re.VERBOSE)

matched = pattern.search(output)

if matched:
    print(matched.group(1))

注意事项

  • 对于正则表达式,我使用的是详细形式,允许我使用注释来注释我的模式。我喜欢这种方式,因为正则表达式很难阅读
  • 在您的系统上,请调整 "configuration-file" 部分以使用您的输出。

【讨论】:

  • 感谢您的详细回答海。在正则表达式中,我们不应该也写它的结尾部分吗?更像是左右边界? configurationFile=/app/log/conf/the_jvm_name.4021.logback.xml .. 我需要在 configurationFile=/app/log/conf.4021.logback.xml 之间,因为数字 4021 也是动态的。所以结尾应该是从.xml
  • 我们可以,但如果这行得通,那我们为什么要做得更多?
猜你喜欢
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 2019-11-30
  • 2014-01-15
相关资源
最近更新 更多