Linux 中基于 Awk 的文件数据过滤

Awk based filtering of data on a file in Linux

我有一个试图通过 awk 过滤的文件数据,我能够过滤数据但希望 awk 语句更简单地写成一行:

文件内容:

Entity Name
Value
Unknown dbs636294051.klm.bet.com: /opt
N/A
Unknown dbs636294051.klm.bet.com: /tmp
N/A
Unknown dbs636294051.klm.bet.com: /var
N/A

我的试用期:

awk  '!/^N/{ if( ~ /klm/) print }' file | awk -F":" '{print }'

以上有效,但我正在寻找是否可以将其修剪到之前的管道:

dbs636294051.klm.bet.com
dbs636294051.klm.bet.com
dbs636294051.klm.bet.com

sub 函数可用于 trim 冒号及其后的任何内容 </code>:</p> <pre><code>awk '!/^N/ && ~ /klm/ {sub(/:.*$/,"",); print }' file

您可以编写单个 awk 命令,将字段分隔符设置为 1 个或多个空格或 :,检查字段 1 是否不以 N 广告开头并且它确实包含 klm

具体来说,你也可以写成^N\/A$

感谢@Renaud Pacalet and @Wiktor Stribiżew 的评论,命令可以如下所示:

awk -F'[[:blank:]]+|:' '!/^N/ &&  ~ /klm/{print }' file

部分

awk -F'[[:blank:]]+|:' '   # Set the field separator to either 1+ spaces or tabs or a semicolon
!/^N/ &&  ~ /klm/        # If the record does not start with `N` and field 2 does contain klm
{print }                 # Print the second column

输出

dbs636294051.klm.bet.com
dbs636294051.klm.bet.com
dbs636294051.klm.bet.com

这是一个快速而肮脏的方法,适用于给定的示例。 如果你有更多的过滤规则,也很容易调整。

awk -F'[:\s]' 'NR>1 && ~/klm/{print }' f
636294051.klm.bet.com
636294051.klm.bet.com
636294051.klm.bet.com

更新,另一种方法:

awk '~/klm/ && (([=11=]=)+sub(/:.*/,""))' f

awk '/Unknown/{gsub(/:/,"",$0);打印 $2}' 文件

当您有两个带有不同字段分隔符的管道 awk 命令时,例如

awk  '!/^N/{ if( ~ /klm/) print }' file | awk -F":" '{print }'

您可以使用 split 函数将其转换为单个 awk 命令,在本例中为

awk  '!/^N/{ if( ~ /klm/){split(,arr,":");print arr[1]}}' file

免责声明:此答案仅适用于将 2 awks 更改为单个,其他改进方法不在本答案的范围内。