我正在尝试使用sed
的awk
模块执行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
的实用程序,但是提供了恒定的系统调用和文件系统操作流。它实时告诉您正在读取,写入哪些文件。
从手册:
NAME
fs_usage
-实时报告与文件系统活动有关的系统调用和页面错误DESCRIPTIONfs_usage实用程序显示有关文件系统活动的系统调用使用情况信息的持续显示。由于需要使用内核跟踪工具,因此它需要root特权。
默认情况下,受监视的活动包括所有系统进程,除了:
fs_usage
,Terminal.app
,telnetd
,telnet
,sshd
,rlogind
,tcsh
,csh
,sh
,zsh
。可以覆盖这些默认值,以便将输出限制为包括或排除(-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
}
问题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='')