当列号不同时,awk 日志文件中的主机名和 IP 地址

当列号不同时,awk 日志文件中的主机名和 IP 地址

这是我的示例文件。实际数据中包含更多数据。

wolf@linux:~$ more log*
::::::::::::::
log1.csv
::::::::::::::
hostname,sn,type,ip,random
abc,a11,zzz,192.168.168.168,rrr
def,e16,yyy,192.168.168.169,fff
ghi,k16,yyy,192.168.168.170,ggg
::::::::::::::
log2.csv
::::::::::::::
hostname,sn,ip,random
abc,a11,192.168.168.168,rrr
def,e16,192.168.168.169,fff
ghi,k16,yyy,192.168.168.170,ggg
wolf@linux:~$ 

某些数据(例如主机名)始终位于第一列。所以,很容易得到它们awk -F, '{print $1}'

wolf@linux:~$ awk -F, '{print $1, $4}' log*
hostname ip
abc 192.168.168.168
def 192.168.168.169
ghi 192.168.168.170
hostname random
abc rrr
def fff
ghi 192.168.168.170
wolf@linux:~$ 

问题是 IP 地址等数据位于不同的列中,具体取决于日志文件中的数据。

如何使用 grep 只获取主机名和 IP 列?

wolf@linux:~$ awk -F, '/def/ {print $1, $4}' log*
def 192.168.168.169
def fff
wolf@linux:~$ 

wolf@linux:~$ awk -F, '/def/ {print $1, $3}' log*
def yyy
def 192.168.168.169
wolf@linux:~$ 

所需输出

def 192.168.168.169
def 192.168.168.169

答案1

如果数据字段位于每个文件的标题行后面,您可以这样做:

awk -F, 'FNR==1{ for(i=1; i<=NF; i++) if($i=="ip") break; next }
               { print $1, $i }' log*.csv

答案2

我最好带:

awk -F, '{for(i=2;i<=NF;i++) if ( $i ~ /^192/ ) printf "%s %s\n",$1,$i ;}'

在哪里

  • 我认为IP以192开头
  • 主机名位于相关字段 1 中
  • 如果有两个或多个IP,则该行将打印两次。

您可以使用if ( $i ~ /^[0-9\.]+$/ )进一步限制 IP(请注意,它也会捕获 12)

答案3

使用csvkit:

$ csvcut -c hostname,ip log1.csv
hostname,ip
abc,192.168.168.168
def,192.168.168.169
ghi,192.168.168.170
$ csvcut -c hostname,ip log2.csv
hostname,ip
abc,192.168.168.168
def,192.168.168.169
ghi,yyy

csvcut命令的工作方式有点像标准cut命令,但可以使用标题信息来提取命名列。

请注意,这依赖于每个文件中的标头实际上是否正确。

答案4

当您的文件带有标题时,通常最好首先创建标题标记(名称)到字段(列)顺序的映射,如f[]下面的数组中存储的那样,然后您可以通过取消引用由字段索引的数组来简单地获取字段值姓名。这样,无论每个输入文件中的列的顺序如何,您的脚本都将正常工作:

$ cat tst.awk
BEGIN { FS="," }
FNR==1 {
    delete f
    for (i=1; i<=NF; i++) {
        f[$i] = i
    }
    next
}
$(f["hostname"]) == h { print $(f["hostname"]), $(f["ip"]) }

$ awk -v h='def' -f tst.awk log*.csv
def 192.168.168.169
def 192.168.168.169

相关内容