awk 并非简单的命令,而是一门专为文本处理设计的编程语言,诞生于20世纪70年代的贝尔实验室,名字取自三位创始人Alfred Aho、Peter Weinberger、Brian Kernighan的姓氏首字母。而Alfred Aho也是著名的编译原理(龙书)的作者。
在Linux世界里,文本处理是运维、开发绕不开的日常——从分析日志、提取配置信息到统计数据,都需要高效的工具支撑。而awk 凭借“按字段处理”的核心能力,成为了比grep(单纯匹配)、sed(整行编辑)更灵活的“文本处理瑞士军刀”。作为一款强大的文本分析语言,也是Linux和Unix环境中功能最强大的数据处理工具,没有之一。
awk '/pattern/ {action}'
| 变量名 | 含义 |
|---|---|
| ARGC | 命令行变元个数 |
| ARGV | 命令行变元数组 |
| FILENAME | 当前输入文件名 |
| FNR | 当前文件中的记录号 |
| FS | 输入列记录分隔符,默认为一个空格 |
| RS | 输入行记录分隔符,默认为\n |
| NF | 当前记录里列个数 |
| NR | 目前为止行记录数 |
| OFS | 输出列记录分隔符 |
| ORS | 输出行记录分隔符 |
awk '/101/' file awk '/101/,/105/' file awk '$1 == 5' file awk '$1 == "CT"' file #注意必须带双引号 awk '$1 * $2 >100 ' file awk '$2 >5 && $2<=15' file
awk '{print NR,NF,$1,$NF,}' file
awk '/101/ {print $1,$2 + 10}' file #显示文件file的匹配行的第一、二个域加10。
awk '/101/ {print $1$2}' file
awk '/101/ {print $1 $2}' file #显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
df | awk '$4>1000000'
awk -F "|" '{print $1}' file
awk 'BEGIN {FS="[: \t|]"} {print $1,$2,$3}' file #通过设置输入分隔符(FS="[: \t|]")修改输入分隔符。
Sep="|"
awk -F $Sep '{print $1}' file #按照环境变量Sep的值做为分隔符。
awk -F '[ :\t|]' '{print $1}' file #按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
awk -F '[][]' '{print $1}' file #按照正则表达式的值做为分隔符,这里代表[、]
awk -f awkfile file
cat awkfile
/101/{print "\047 Hello! \047"} # 遇到匹配行以后打印 ' Hello! ' \047代表单引号。
{print $1,$2} # 因为没有模式控制,打印每一行的前两个域。
awk '$1 ~ /101/ {print $1}' file
awk '$1 * $2 >100 {print $1}' file
awk 'BEGIN { OFS="%"} {print $1,$2}' file
if (表达式1)
表达式2
else
表达式3
BEGIN 表示在处理任意行之前进行的操作。
awk 'BEGIN { max=100 ;print "max=" max} {max=($1 >max ?$1:max); print $1,"Now max is "max}' file
awk '{print ($1>4 ? "high "$1: "low "$1)}' file
awk '$1 == "Chi" {$3 = "China"; print}' file
awk '{$7 %= 3; print $7}' file # 将第7域被3除,并将余数赋给第7域再打印。
awk '/tom/ {wage=$2+$3; printf wage}' file
awk '/tom/ {count++;}
END {print "tom was found "count" times"}' file
awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4;
END {print "The total is $" cost>"filename"}' file
1 2 3 $1,200.00 1 2 3 $2,300.00 1 2 3 $4,000.00
awk '{gsub(/\$/,"");gsub(/,/,"");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
awk '{gsub(/\$/,"");gsub(/,/,"");
if ($4>3000&&$4<4000) exit;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
awk '{gsub(/\$/,"");gsub(/,/,"");
if ($4>3000) next;
else c4+=$4; }
END {printf "c4=[%d]\n",c4}"' file
格式为: 打印文件并前置文件名。
awk '{ print FILENAME,$0 }' file1 file2 file3 > fileall
awk ' $1!=previous { close(previous); previous=$1 }
{print substr($0,index($0," ") +1)>$1}' fileall
awk 'BEGIN {"date"|getline d; print d}'
awk 'BEGIN {system("echo \"Input your name:\\c\"");
getline d;print "\nYour name is",d,"\b!\n"}'
awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'
awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file
awk '{ for(i=1;i<NF;i++) {print NF,$i}}' file
type file|awk -F "/" '
{ for(i=1;i<NF;i++)
{ if(i==NF-1) { printf "%s",$i }
else { printf "%s/",$i } }}'
awk 'BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
printf "\n%d月份\n",j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf "%02d%02d ",j,i}
}
}
}'
vmstat -n 1 10|awk '/[0-9*]/ && $11 > 10 { cs_tal+=$12; int_tal+=$11; num++ } END{print "ContextSwitch: ",cs_tal/num, "Interrupt: ", int_tal/num}' # ContextSwitch: 15342 / 9 = 1704.67 Interrupt: 2151.33
#!/bin/sh sum=0 str="" for i in $(sed -n -e '/TunnelPorts/s:.*ports="\([^"]*\).*:\1,53,443,80,7193:' \ -e 's:,:\n:gp' a | sort -ru -n); do sum=$((sum+1)) str="$i,$str" done str=${str%,} echo "<TunnelPorts count=\"$sum\" ports=\"$str\" />"
iptraf -i eth1 -t 1 -B -L eth1.log
#!/bin/sh DEV=$1 PORT=$2 TIME=$3 [ -z $TIME ] && TIME=1 [ -z $DEV ] && echo "$0 ethx port time" && exit 0 IP=`ifconfig $DEV|grep "inet addr"|sed -r 's#.*addr:(.*) Bcast.*#\1#g'` [ ! -z $PORT ] && IP="$IP:$PORT" FILE="/tmp/$DEV.log" SORT="10" LIMIT="0" get_bad_ip() { awk '/\*\*\*/{next} { if($11~/^'"$NET"'/ && $13~/^'"$IP"'/) f="O_IN"; if($13!~/^'"$NET"'/) f="OUT"; if($11!~/^'"$NET"'/) f="IN"; gsub("(:[^ ]*)?(;)?",""); t=$6":"f" "$11; a[t]+=$8 } END { for(i in a) print i,a[i]}' $FILE | sort -k3nr | \ awk '{a[$1]++; if(a[$1]<'"$SORT"' && ($3-'"$LIMIT"')>0 ) \ b[$1]=b[$1]"\n"a[$1]" "$2" "$3" bytes" } END{ for(i in b) if(i!~/^:/) print i""b[i]"\n" }' } rm -rf /var/lock/iptraf/iptraf* rm -rf $FILE iptraf -i $DEV -t $TIME -B -L $FILE && renice -18 `pidof iptraf` sleep $TIME kill -9 `pidof iptraf` get_bad_ip
#!/bin/sh IP="10.4.1.1" NET="10.4.1" FILE="/var/log/iptraf/eth1.log" SORT="4" LIMIT="700" awk '/\*/{next} { if($11~/^'"$IP"'/ && $13~/^'"$NET"'/) f="O_OUT"; if($11~/^'"$NET"'/ && $13~/^'"$IP"'/) f="O_IN"; if($13!~/^'"$NET"'/) f="OUT"; if($11!~/^'"$NET"'/) f="IN"; gsub("(:[^ ]*)?(;)?",""); t=$6":"f" "$11; a[t]+=$8 } END { for(i in a) print i,a[i]}' $FILE | sort -k3nr | \ awk '{a[$1]++; if(a[$1]<'"$SORT"' && ($3-'"$LIMIT"')>0 ) \ b[$1]=b[$1]"\n"a[$1]" "$2" "$3" bytes" } END{ for(i in b) if(i!~/^:/) print i""b[i]"\n" }'
-bash-3.00# cat /tmp/tcp_remote eth0 21 eth0 80 eth0 22 eth0 21 eth0 22 eth0 53 eth0 7193 eth0 80 eth0 443 eth0 9001 eth0 53 eth0 7193 eth0 80 eth0 443 eth0 21 eth0 9001
cat /tmp/tcp_remote |sort|uniq|awk '{a[$1]=a[$1](a[$1]?",":"@")$2}END{for (j in a) print j a[j]}'
awk '!seen[$0]++' text > sort.txt
netstat -antu | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' LAST_ACK 14 SYN_RECV 348 ESTABLISHED 70 FIN_WAIT1 229 FIN_WAIT2 30 CLOSING 33 TIME_WAIT 18122
| 状态 | 描述 |
|---|---|
| CLOSED | 无连接是活动的或正在进行 |
| LISTEN | 服务器在等待进入呼叫 |
| SYNRECV|一个连接请求已经到达,等待确认| |SYNSENT | 应用已经开始,打开一个连接 |
| ESTABLISHED | 正常数据传输状态 |
| FINWAIT1|应用说它已经完成| |FINWAIT2 | 另一边已同意释放 |
| ITMEDWAIT|等待所有分组死掉| |CLOSING|两边同时尝试关闭| |TIMEWAIT | 另一边已初始化一个释放 |
| LAST_ACK | 等待所有分组死掉 |
#!/bin/sh DEFINE="ESTABLISH#100 FIN_WAIT#100 TIME_WAIT#100 SYN_RECV#100" for STATE in ESTABLISH TIME_WAIT FIN_WAIT SYN_RECV;do NUM=0 echo ------------------ $STATE -------------------- netstat -antu|sed 's/::ffff://g'|grep $STATE|awk '{print $5}'|cut -d: -f1| \ awk '{++S[$1]} END{for(a in S) \ if( system("grep "a" /etc/whitelist.txt >/dev/null") != 0 && S[a]>'$NUM' ) print a"\t\tconnect num: "S[a]}' done for i in $DEFINE;do STATE=`echo $i|awk -F# '{print $1}'` NUM=`echo $i|awk -F# '{print $2}'` PORT=`echo $i|awk -F# '{print $3}'` if [ -z $PORT ];then netstat -antu|sed 's/::ffff://g'|grep $STATE|awk '{print $5}'|cut -d: -f1|awk '{++S[$1]} END{for(a in S) \ if( system("grep -q "a" /etc/whitelist.txt" ) != 0 && S[a]>'$NUM' ) print a" "S[a]" ""'$STATE'"" "'$NUM'}'| \ xargs -I[] /usr/sbin/record_ddos.sh [] # 调用另一个程序来分析数据并处理 else netstat -antu|sed 's/::ffff://g'|grep :$PORT|grep $STATE|awk '{print $5}'|cut -d: -f1|awk '{++S[$1]} END{for(a in S) \ if( system("grep -q "a" /etc/whitelist.txt" ) != 0 && S[a]>'$NUM' ) print a" "S[a]" ""'$STATE'"" "'$NUM'}'| \ xargs -I[] /usr/sbin/record_ddos.sh [] fi done # whitelist.txt是白名单
TMP=1234 awk '{print "'$TMP'",$0}' urfile
TMP=1234 awk -v var=$TMP '{print var,$0}' urfile
awk -v N=$(wc -l < file.txt) 'NR<=3 || NR>=(N-2)' file.txt
KEYS=$(sort -k1 /tmp/download.log | awk '/download/{print $1}' | \ uniq -c|awk '{if($1>3) {st=index($2,"key"); \ print substr($2,st+4,36)}}')
awk '{split($7,a,"/");b[a[3]]+=$10} END{for(i in b) print i,b[i]}' /disk/ssd1/logs/b0.upaiyun.com.access.log|sort -k2nr |head -30 \ | awk '{print $1}'| nslookup| awk '/Non-authoritative answer/{getline;if($1~/upaiyun/) r=$1;else r=$NF; \ split(r,a,"."); rr=a[1]"."a[2]; print rr}' | sed -r 's@>@\n@g'|sort -u