awk 命令使用示例

本文介绍了一种使用Linux脚本配合awk脚本来分析日志的示例,包括离线次数统计、登录记录排序以及离线时间追踪,展示了awk的强大文本处理能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

awk 是一个文本处理的利器,功能十分强大,awk的脚本可以使用类似c语言的语法编程。内置很多丰富的函数,处理文本十分方便。

下面是我使用linux脚本配合awk脚本写的分析日志的示例,日后可以作为参考。

log_analysis.sh日志分析脚本:

#!/bin/bash
# 日志分析工具
# 使用方法:只需要把日志和本脚本放在同一个目录,然后执行:./log_analysis.sh
# 本脚本需要配合cal.awk文件使用,cal.awk为awk命令的脚本文件

#先查找离线信息
OFFLINE_LIST=`grep -i "offline,hasConneId" *.log | awk -v f1='[' -v f2='Dcm(' '{ time=substr($0,index($0,f1)+1,19); v=substr($0,index($0,f2)+length(f2)); dcmNo=substr(v,1,index(v,")")-1); printf("%s %s\\n",time,dcmNo);}'`
# 也可以用sed命令来实现: grep "offline,hasConneId" *.log | sed -e 's/^.*:\[//' | sed -e 's/\]\[.*Dcm(/ /' | sed -e 's/) (.*$//'
#使用时用(双引号一定要加,否则会打印成一行): echo -e "$OFFLINE_LIST"

#统计离线次数,并按离线次数从大到小排序
OFFLINE_STA=`echo -e "$OFFLINE_LIST" | awk '{a[$2]++} END{for(key in a){print "dcmNo: "key, "离线次数: "a[key] | "sort -rn -k 4"}}'`

# 输出
echo "==========离线次数统计=========="
echo -e "$OFFLINE_STA"

# 查找登录记录,并按时间排序
LOGIN_LIST=`grep -i "Login check" *.log | awk -v f1='[' -v f2='dcmNo:' '{ time=substr($0,index($0,f1)+1,19); v=substr($0,index($0,f2)+length(f2)); dcmNo=substr(v,1,index(v,f1)-1); printf("%s %s\n",time,dcmNo);}' | sort -k 1`

# 依次查找掉线记录及掉线持续时间
echo -e "$OFFLINE_LIST" | awk -v loginList="$LOGIN_LIST" -f cal.awk

#测试cal.awk脚本
#echo -e "20220320_042811_327 869516056100980" | awk -v loginList="20220320_042810_327 869516056100980\n20220320_042813_327 869516056100980" -f cal.awk




cal.awk脚本:

#!/bin/awk -f
BEGIN{
	print "==========离线时间统计========";
	LINE_NUM=1;
} 
{
cmd=sprintf("echo -e \"%s\"|grep %s",loginList,$2); 
n=1;
#将命令的输出逐行写入到arr数组
while(cmd|getline tmpStr)
{
	arr[n++]=tmpStr;
};
close(cmd);
#将字符串的时间转换为时间戳
timeStr=$1;
year=substr(timeStr,1,4);
month=substr(timeStr,5,2);
day=substr(timeStr,7,2);
hour=substr(timeStr,10,2);
minute=substr(timeStr,12,2);
sec=substr(timeStr,14,2);
tsOffline=mktime(sprintf("%s %s %s %s %s %s",year,month,day,hour,minute,sec));

found=0;
strOfflineTime=strftime("%Y-%m-%d %H:%M:%S",tsOffline);
	for(k in arr)
	{
	split(arr[k],arrItem," ");
	timeStr=arrItem[1];
	year=substr(timeStr,1,4);
	month=substr(timeStr,5,2);
	day=substr(timeStr,7,2);
	hour=substr(timeStr,10,2);
	minute=substr(timeStr,12,2);
	sec=substr(timeStr,14,2);
	tsLogin=mktime(sprintf("%s %s %s %s %s %s",year,month,day,hour,minute,sec));
	if(tsLogin >= tsOffline)
	{
		found=1;
		strLoginTime=strftime("%Y-%m-%d %H:%M:%S",tsLogin);
		printf("%d dcmNo: %s 离线时间: %s 最近登录时间: %s 离线持续时间: %d 秒\n", LINE_NUM++,$2,strOfflineTime,strLoginTime,tsLogin-tsOffline);
		break;
	}
	}
	if(0 == found)
	{
		printf("%d dcmNo: %s 离线时间: %s 最近登录时间: not_found 离线持续时间: - 秒\n", LINE_NUM++,$2,strOfflineTime);
	}
}

其中用到awk比较关键的点:

1、 如何在awk脚本内部调用shell命令

在awk脚本内存调用shell命令,有几种做法

(1)第一种方法:使用system脚本函数

ps -ef | grep redis | awk '{ cmd="kill -9 "$2;system(cmd) }'

在awk执行体的内部,引用变量,不需要加$符号

如果执行完命令后,需要获取命令的返回值,可以在system()命令前用 var=system();获取,例如:

ps -ef | grep redis | awk '{ cmd="kill -9 "$2; cmd_return_value=system(cmd) }'

system函数的返回值只是表示命令成功和失败,通常是一个int类型的值

2第二种方法:拼接命令然后直接执行

除了可以使用system函数执行shell命令之外,还可以直接拼接命令存放到一个变量中,然后执行,如:

ps -ef | grep IOV-NAddSMS | grep -v grep | awk '{ cmd="basename "$8; cmd|getline exename;}'

(3)执行完命令后捕获输出

  【1】执行命令后捕获输出使用awk 的getline命令

在awk脚本内部执行shell命令后,捕获输出使用管道和getline命令,如:

ps -ef | grep IOV-NAddSMS | grep -v grep | awk '{ cmd="basename "$8; cmd|getline exename;}'

这样命令输出就会存放到exename这个变量中,而不是输出到屏幕中

注意:getline只会获取到一行的输出,如果获取所有的输出需要使用循环

 【2】使用getline捕获多行输出

例子如下:

[root@localhost log]# echo "" | awk '{cmd="ls -l"; while(cmd|getline lineData){printf("line:%s\n",lineData);};close(cmd);}'

line:总用量 27976

line:-rw-r--r--. 1 root root  1737084 4月   6 19:20 20220320.tar.gz

line:-rw-r--r--. 1 root root     1392 4月   7 10:24 cal.awk

line:-rwxr-xr-x. 1 root root        0 3月  20 00:00 ErrorLog.log

line:-rwxr-xr-x. 1 root root 16791268 3月  20 13:03 261.log

line:-rwxr-xr-x. 1 root root 10100762 3月  21 00:09 366.log

line:-rwxr-xr-x. 1 root root     1453 4月   7 10:30 log_analysis.sh

2、awk 脚本内部如何获取外部变量

awk获取外部变量的方法,其中一种方法可以使用awk自带的-v参数,将外部变量转换成内部变量,相当于传递变量值

例如:

[root@KF-CFT-mongdb3 Script]# echo $myvar

IOV-NAddSMS

[root@KF-CFT-mongdb3 Script]# date | awk -v var=$myvar '{ print var }'

IOV-NAddSMS

[root@KF-CFT-mongdb3 Script]#

3、awk 数组

【1】awk数组支持任意类型作为下标,例如下面的数组就是合法的:arr[“name”]=”jkm”

【2】数组遍历

awk的数组都是类似于map,key<->value的形式,如果是普通的数组,key(即下标)为1~n的数字,key也可以是字符串或者其他类型。

遍历数组的格式如下:

[root@localhost log]# echo " " | awk '{arrStr="hello\nworld";split(arrStr,arr,"\n"); for(k in arr){print k,arr[k]}}'

1 hello

2 world

4、使用awk 去除重复行

比较简洁的写法是下面这样:

echo -e "aaa\nbbb\naaa" | awk '!a[$0]++'

但是上面的写法比较难理解,比较易懂的写法如下:

echo -e "aaa\nbbb\naaa" | awk '{ if (!a[$0]++) { print $0 } }'

5、awk 脚本内部给外部变量赋值

awk可以给外部变量赋值,使用awk的内置命令printf命令合成赋值语句,然后使用eval命令将文本的赋值语句执行,成为shell的变量,例如:

[root@localhost ~]# eval `echo "hello world" | awk '{ printf("VAR1=%s\nVAR2=%s",$1,$2); }'`

[root@localhost ~]# echo $VAR1

hello

[root@localhost ~]# echo $VAR2

world

其中printf函数中的\n换行符是必须的,因为必须要每个变量占用一行

其中,eval可以这么用

[root@localhost ~]# eval VAR1=45

[root@localhost ~]# echo $VAR1

即可以把文本的赋值语句转成实际的变量

参考文档:

linux awk 内置函数详细介绍(实例) - 程默 - 博客园 (cnblogs.com)

AWK 数组 | 菜鸟教程 (runoob.com)

AWK 内置函数 | 菜鸟教程 (runoob.com)

Linux awk 命令 | 菜鸟教程 (runoob.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值