如何使用awk按第一个非空白字符将文本文件拆分为记录并仅打印包含字符串的记录

如何使用awk按第一个非空白字符将文本文件拆分为记录并仅打印包含字符串的记录

我有一个文本文件,其中的信息按块分隔。我想将这些块分成记录,以便我可以单独处理它们。

这是我的文本文件(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

相关内容