如何将stdin直接传送到python并像grep一样进行解析?

问题描述 投票:2回答:1

我正在尝试使用sedawk模块执行python3 / re样式的正则表达式替换。

您可以在此处使用硬编码的测试字符串来正常工作:

#!/usr/bin/env python3

import re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

line = ("21:21:54.165651  stat64   this/                       0.000012         THiNG1.12471\n"
        "21:21:54.165652  stat64   /that                       0.000012         2thIng.12472\n"
        "21:21:54.165653  stat64   /and/the  other  thing.xml  0.000012  With  S paces.12473\n"
        "21:21:54.165654  stat64   /and/the_other_thing.xml    0.000012    without_em_.12474\n"
        "21:59:57.774616  fstat64           F=90               0.000002            tmux.4129\n")

result = re.sub(regex, subst, line, 0, re.MULTILINE)

if result:
        print(result)

但是我在使其与标准输入相同的方式时遇到了一些麻烦:

#!/usr/bin/env python3

import sys, re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

for line in str(sys.stdin):
        #sys.stdout.write(line)
        result = re.sub(regex, subst, line, 0, re.MULTILINE)

if result:
        print(result,end='')

我希望能够将输入从另一个实用程序直接输入到它,就像grep和类似的CLI实用程序常见的那样。

知道这个问题在哪里吗?


附录

我试图使问题简单化和泛化,希望答案在相​​似但不同的情况下可能更有用,并且对更多人有用。但是,详细信息可能会进一步阐明该问题,因此在此我将包括当前情况的确切详细信息:

我的脚本所需的输入实际上是来自名为fs_usage的实用程序的输出流,它类似于ps的实用程序,但是提供了恒定的系统调用和文件系统操作流。它实时告诉您正在读取,写入哪些文件。

从手册:

NAMEfs_usage-实时报告与文件系统活动有关的系统调用和页面错误

DESCRIPTIONfs_usage实用程序显示有关文件系统活动的系统调用使用情况信息的持续显示。由于需要使用内核跟踪工具,因此它需要root特权。

默认情况下,受监视的活动包括所有系统进程,除了:fs_usageTerminal.apptelnetdtelnetsshdrlogindtcshcshshzsh。可以覆盖这些默认值,以便将输出限制为包括或排除(-e)用户指定的进程列表。

fs_usage呈现的输出将根据您的窗口大小进行格式化。一个狭窄的窗口将显示较少的列。使用宽的窗口以显示最大数据。您可以通过使用-w选项强制进行宽屏显示来覆盖格式限制。在这种情况下,当窗口不够宽时,显示的数据将自动换行。

我一起整理了一个粗糙的bash脚本,以从流中提取进程名称,并将其转储到临时日志文件中。您可以将其视为过滤器或提取器。这是一个直接转储到stdout的函数(删除最后一行的注释以转储到文件)。

proc_enum ()
  {
  while true; do
  sudo fs_usage -w -e 'grep' 'awk' | 
    grep -E -o '(?:\d\.\d{6})\s{3}\S+\.\d+' | 
    awk '{print $2}' | 
    awk -F '.' '{print $1}' \
      #>/tmp/proc_names.logx
  done
  }

有用的链接

python regex python-3.x pipe stdin
1个回答
0
投票

问题str(sys.stdin) Python将在for循环中执行的操作是:

 i = iter(str(sys.stdin))
 # then in every iteration
 next(i)

这里您将方法转换为str,导致我的计算机为:

str(sys.stdin) == "<_io.TextIOWrapper name='<stdin>' mode='r' encoding='cp1256'>"

您没有在stdin接收的行上循环,而是在函数的字符串表示形式上循环。

还有第一个示例中的另一个问题,您正在对整个文本应用re.sub但是这里您要申请每一行,所以您应该将每一行的结果串联起来在应用re.sub之前,请在单行中插入或合并行。

import sys, re

regex = r"^(?P<time>\d+\:\d+\:\d+\.\d+)(?:\s+)(?P<func>\S+)(?:\s+)(?P<path>\S+(?: +\S+)*?)(?:\s+)(?P<span>\d+\.\d+)(?:\s+)(?P<npid>(?P<name>\S+(?: +\S+)*?)\.(?P<pid>\d+))\n"
subst = "'\\g<name>', "

result = ''
for line in sys.stdin:
    # here you should convert the input but I think is optional
    line = str(line)
    result += re.sub(regex, subst, line, 0, re.MULTILINE)


if result:
    print(result, end='')
© www.soinside.com 2019 - 2024. All rights reserved.