我有一个文本文件,其中的信息按块分隔。我想将这些块分成记录,以便我可以单独处理它们。
这是我的文本文件(file.txt):
Alarm Stats:
com.android.calendar
38ms running, 0 wakeups
1 alarms: act=com.android.calendar.APPWIDGET_SCHEDULED_UPDATE dat=content://com.android.calendar typ=vnd.
com.android.providers.calendar
2ms running, 2 wakeups
2 alarms: act=com.android.providers.calendar.intent.CalendarProvider2 flg=0x14
android
35563ms running, 11 wakeups
1 alarms: act=android.intent.action.DATE_CHANGED flg=0x20000014
1210 alarms: act=android.intent.action.TIME_TICK flg=0x40000014
120 alarms: act=com.android.server.ThrottleManager.action.POLL flg=0x14
1 alarms: act=android.net.wifi.DHCP_RENEW flg=0x14
10 alarms: act=android.content.syncmanager.SYNC_ALARM flg=0x14
com.apollo.apollonetworkcheck
1026ms running, 88 wakeups
88 alarms: flg=0x14
com.android.phone
4ms running, 0 wakeups
2 alarms: act=com.android.phone.UPDATE_CALLER_INFO_CACHE flg=0x14
使用“apollo”作为我的搜索字符串,输出应该是:
com.apollo.apollonetworkcheck
1026ms running, 88 wakeups
88 alarms: flg=0x14
到目前为止,我的命令行已经有了这个,但我不知道在哪里放置搜索字符串“apollo”。另外,我不知道如何为记录分隔符指定“非空白”。
$ awk 'BEGIN { RS = "^RTC" } { print $1 }' file.txt
Archemar、wurtel、steeldriver、terdon,你们的答案很棒,为问题添加了很多内容和资源解决方案。我对每个答案都投了赞成票,因为它很有价值。当然,带有“gawk”的命令更准确地表达了使用 unix/linux 命令的问题和目标。
答案1
我总是把 perl 放在所有事情上:-)
perl -ne 'if (/^\s/) { $x.=$_ }else{print $x if $x=~/apollo/; $x=$_} END {print $x if $x=~/apollo/}' file.txt
编辑:一行的解释:
- -n 表示对输入进行循环,默认情况下不在每个循环结束时打印(-p 相同,但默认情况下打印该行)。
- -e 指定表达式或代码片段。这是在隐式循环内执行的。
- 我使用 $x 变量来缓冲输入文本,直到找到完整的“记录”。
- /^\s/ 匹配行开头的空格。如果找到,输入行将添加到 $x 缓冲区。如果没有,则“记录”完成并检查搜索字符串“apollo”。如果找到,则打印记录。缓冲区在处理后被清除。
- END {} 部分在循环完成后执行,以处理输入中最后一条记录的情况。
答案2
您使用正则表达式记录分隔符的想法很优雅,但请记住 awk 将消耗相应的文本,在您的情况下,这将是该文本的第一个非空白字符下列的记录。
如果您的系统有 GNU 版本的 awk,您可以通过变量访问最近匹配的 RS RT
,但是您仍然需要保存结果以便将其缝合回以下记录的开头 - 也许类似于
gawk 'BEGIN{RS="\n[^[:blank:]]"}; {lastRT=RT}; /apollo/ {$0=substr(lastRT,2)""$0; print}' file.txt
justsubstr(lastRT,2)
从匹配中删除换行符,以便仅在前面添加非空白字符。
答案3
使用 awk 和一个参数
(文件过滤器.awk)
BEGIN { p=0 ; } # no printing
{ if ( (substr($0,1,1) != " ") && (substr($0,1,1) != "\t" ) ) p=0 ; # if no blank stop printing
if ( index($0,name) > 1 ) p=1 ; # pattern found ?
if (p) print ;
}
- $0 是整行
- substr($0,1,1) 是该行的第一个字符
和结果
awk -v name=apollo -f filter.awk a.txt
com.apollo.apollonetworkcheck
1026ms running, 88 wakeups
88 alarms: flg=0x14
答案4
我也会把 perl 放在所有东西上,但有时会添加sed
一些调味品:
$ sed 's/^\w/\n&/' file | perl -000ne 'print if /apollo/'
com.apollo.apollonetworkcheck
1026ms running, 88 wakeups
88 alarms: flg=0x14
这sed
将在每条记录之间添加额外的换行符。它只是查找以字母数字字符 ( ^\w
) 开头的行,然后用换行符替换该字符,后跟该字符本身(\n&
,&
意思是“您刚刚匹配的内容”)。结果是一个文件,其中的记录看起来像段落,它们前面有一个空行。
我们现在可以使用 Perl 的“段落模式”,由 激活-000
。结合-n
(逐条记录读取输入记录),这使我们能够一次读取整个记录。因此,我们需要做的就是打印当前“行”(记录)(如果它与所需的模式匹配)。在这种情况下apollo
。
我不确定该\w
符号的可移植性如何。如果你sed
无法处理它,请使用这个:
sed 's/^[^ \t]/\n&/' file | perl -000ne 'print if /apollo/'
您还可以使用相同的方法awk
:
$ sed 's/^[^ \t]/\n&/' file | awk -v RS="\n\n" '/apollo/'
com.apollo.apollonetworkcheck
1026ms running, 88 wakeups
88 alarms: flg=0x14