西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网
当前位置: 主页 > 开发教程 > linux教程 >

Linux之awk命令详解

时间:2016-04-29 00:01来源:未知 作者:好模板 点击:
awk的工作原理 一次读取一行文本,按输入分隔符进行切片,切成多个组成部分,将每片直接保存在内建的变量中,$1,$2,$3....,引用指定的变量,可以显示指定断,或者多个断。如果需要

awk的工作原理

一次读取一行文本,按输入分隔符进行切片,切成多个组成部分,将每片直接保存在内建的变量中,$1,$2,$3....,引用指定的变量,可以显示指定断,或者多个断。如果需要显示全部的,需要使用$0来引用。可以对单个片断进行判断,也可以对所有断进行循环判断。其默认分隔符为空格

awk的基本用法格式

  • awk [options] 'program' FILE......
    • 语句之间用分号分隔
  • [options]
    • -F : 指明输入时用到的字段分隔符
    • -v var=VALUE : 自定义变量
      • 在awk中变量的引用不需要加$,而是直接引用

awk用法的简要介绍

  • 第一种模式
    • awk [options] 'scripts' file1,file2.....

      在这种模式中,scripts主要是命令的堆砌,对输入的文本行进行处理,通过命令print,printf或是输出重定向的方式显示出来,这里经常用到的知识点是:awk的内置变量,以及命令print和printf的使用

  • 第二种模式
    • awk [options] 'PATTERN{action}' file,file2.....

      在这种模式中,最重要的是5种模式和5种action的使用,以及awk的数组的使用和内置函数

第一种模式

1、print
  • 1、各项目之间使用逗号隔开,而输出时则以空白字符分隔
  • 2、输出的Item可以为字符串或数值,当前记录的字段(如$1)、变量或awk的表达式,数值会先转换为字符串,而后再输出
  • 3、print命令后面的Item可以省略,此时其功能相当于print $0,因此,如果想输出空白行,则需要使用print""
  • 4、如果引用变量$1或其他的,是不能使用引号引起来
2、内置变量
  • FS : input field seperator,输入的分隔符,默认为空白字符
  • OFS: output field seperator,输出的分隔符,默认为空白字符
  • RS : input record seperator,输入的换行符
  • ORS: output record seperator,输出时的换行符
  • NF : number of field ,字段个数
    • awk '{print NF}' /etc/fstab :打印每行的最后一个字段为第几个字段,这里是数量引用,不是对应的值引用
    • awk '{print $NF}' /etc/fstab : 打印每行中的最后一个字段
  • NR : number of record,文件中的行数

    • awk '{print NR}' /etc/fstab: 打印行号,其会个行号都显示
    • awk 'END{print NR}' /etc/fstab: 显示文本的总行数,其只是在文本处理完成后,只显示一次行号
    • awk '{print NR}' file1 file2 : 会每把所有文档进行总的编号,而不是单独对文件进行编号
  • FNR : 对每个文件进行行数单独编号

    • awk '{print FNR}' file1 file2 : 会对每个文件的行数进行单独的编号显示
  • FILENAME : awk命令所处理的文件的名称
    • awk '{print FILENAME}' file1 : 显示当前文件名,但会每行显示一次
    • awk 'END{print FILENAME}' file1 : 显示当前文件名,但只会显示一次
  • ARGC : 命令行中参数的个数,其awk命令也算一个参数
    • awk 'END{print ARGC}' /etc/fstab : 显示共有几个参数
  • ARGV : 其是一个数组,保存的是命令行所给定的各参数
    • awk 'END{print ARGV[0]}' /etc/fstab : 显示第一个参数,默认第一个参数个awk命令本身
3、自定义变量
  • -v var=VALUE : 在选项位置定义
  • awk 'BEGIN{test="hello";print test}' : 在program中定义

      变量在program中定义时,需要使用引号引起来
4、printf命令
  • 其格式化输出:printf FORMAT,item1,item2....
要点:
  • 1、其与print命令最大不同是,printf需要指定format
  • 2、printf后面的字串定义内容需要使用双引号引起来
  • 3、字串定义后的内容需要使用","分隔,后面直接跟Item1,item2....
  • 4、format用于指定后面的每个item的输出格式
  • 5、printf语句不会自动打印换行符,\n
格式符
  • %c: 显示字符的ASCII码
  • %d,%i : 显示十进制整数
  • %e,%E: 科学计数法数值显示
  • %f : 显示为浮点数
  • %g,%G: 以科学数法或浮点形式显示数值
  • %s: 显示字符串
  • %u: 无符号整数
  • %%: 显示%号自身,相当于转义
修饰符
  • N : 显示宽度
  • - : 左对齐(默认为右对齐)
  • + : 显示数值符号
  • 示例:
    • awk -F: '{printf "%s\n",$1}' /etc/fstab
    • awk -F: '{printf "username: %s,UID:%d\n",$1,$3}' /etc/passwd
    • awk -F: '{printf "username: %-20s shell: %s\n",$1,$NF}' /etc/passwd
输出重定向
  • print items > "output-file"
  • print items >> "output-file"
  • print items | command

      特殊文件描述符:
      /dev/stdin :标准输入
      /dev/stdout:标准输出
      /dev/stderr:错误输出
      /dev/fd/N : 某特定文件描述符,如/dev/stdin就相当于/dev/fd/0
* 示例
* awk -F: '{printf "%-15s %i\n",$1,$3 > "/dev/stderr"}' /etc/passwd

第二种模式

  • awk [option] 'PATTERN{action}' file1,file2....
PATTERN的使用
  • REGEXP:正则表达式,格式为/regular expression/,仅处理能够被此处模式匹配到的行

      awk '/^UUID/{print $1}' /etc/fstab
      awk '!/^UUID/{print $1}' /etc/fstab
  • relational expression:表达式,其值非0或为非空字符时满足条件,用运算符~(匹配)和!~(不匹配)

      $1 ~ /foo/ 或者 $1 == "magedu"
  • Ranges : 指定匹配范围,格式为/pat1/,/pat2/

      awk -F: '{NR>=2&&<=10){print $1}' /etc/passwd
      awk -F: /^root/,/^myuser/{print $1}' /etc/passwd
      注意:不支持直接给出数字的格式
  • BEGIN/END模式 : 特殊模式,仅在awk命令执行前运行一次或结束前运行一次

      awk -F: 'BEGIN{print "Username    ID    Shell"}{printf "%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd :先打印一个表头
      awk -F: 'BEGIN{print "username   ID     Shell"}{printf "%-10s%-10s%-20s\n",$1,$3,$7}END{print "end of report."} /etc/passwd :打印一个表尾
  • Empty(空模式):匹配任意输入行

      /正则表达式/:使用通配符的扩展集。
      关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>$1选择第二个字段比第一个字段长的行。
      模式匹配表达式:
      模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
      BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
      END:让用户在最后一条输入记录被读取之后发生的动作。
常见的Action
  • 1)Expressions
  • 2) Control statements :if while等
  • 3) Compound statements:组合语句
  • 4) Input statements
  • 5) Output statements
控制语句
1、if-else
  • 语法:if (condition){then-body} else{[else-body]}
  • 示例:
    • awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
    • awk -F: '{if($3>=1000){printf "Common user: %s\n",$1} else {printf "root or sysuser: %s\n",$1}}' /etc/passwd
    • awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
    • awk -F: '{if(NF>5) print $0}' /etc/fstab
    • df -h | awk -F[%] '/^\/dev/{print $1}' | awk {if($NF>=20) print $1}'
    • awk -F: '{if($1=="root") print $1,"Admin";else print $1, "Common User"}' /etc/passwd
    • awk -F: '{if($1=="root") printf "%-15s: %s\n",$1,"Admin";else printf "%-15s: %s\n",$1, "Common user"}' /etc/passwd
    • awk -F: -v sum=0 '{if($3>=500) sum++}END{print sum}' /etc/passwd : 统计用户ID大于500的有多少行
    • awk -F: -v OFS="\t" '{if($3<=999)printf "Sys user:\t%-15s ID is :%d\n", $1,$3;else{printf "Common user:\t%-15s ID is :%d\n",$1,$3}}' /etc/passwd :可以使用\t制表符控制 输出格式
2、while:用于循环字段的
  • 语法:while (condition){statement1;statment2;....}
  • 示例:
    • awk '/^[[:space:]]*linux16/{print}' /boot/grub2/grub.cfg
    • awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg :对每个字段进行字符个数统计
    • awk '/^[[:space:]]]*linux16/{i=1;while(i<=NF){if(length($i)<=7)print $i,length($i);i++}}' /etc/grub2.cfg
    • awk -F: '{i=1;while(i<=3){print $i;i++}}' /etc/passwd:打印用户名、密码占位符、ID
    • awk -F: '{i=1;while(i<=NF){if(length($i)>=4){print $i};i++}}' /etc/passwd : 字段大小于等于4的都显示
3、do-while
  • 语法:do {statement1,statement2,....} while (dondition)
  • 示例:
    • awk -F: '{i=1;do{print $i;i++}while(i<=3)}' /etc/passwd :打印用户名、密码占位符、UID
4、for
  • 语法:for(variable assignment;condition;iteration process){ statement1,statement2,...}

  • 示例:

    • awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
    • awk -F: '{for(i=1;i<=3;i++)print $i}' /etc/passwd
    • awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd
      5、for循环还可以用来遍历数组元素
  • 语法:for (i in array) {statement1,statement2,....}
  • 示例
    • awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd
    • awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab
    • awk '/^UUID/{filesystem[$3]++}END{for (i in filesystem) {print i,filesystem[i]}}' /etc/fstab :统计/etc/fstab中各文件系统的次数
    • netstat -tan | awk '/^tcp>/{state[$NF]++}END{for(i in state) {print i,state[i]}}' : 统计各连接状态的次数
    • awk '{ip[$1]++} END {for (i in ip) {print i,ip[i]}}' /var/log/httpd/access_log : 统计访问日志中各IP的访问次数
6、case
  • 语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
7、break和continue
  • break [n]
  • continue : 进入下一个字段
8、next
  • 功能:提前结束本行文本的处理,并接着处理下一行
  • 示例:
    • awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
    • awk -F: ‘{if ($3%2!=0) next;print $1,$3}’ /etc/passwd
awk的操作符
  • 1、算术操作符
    • -x : 负值
    • +x : 转换为数值
    • x^y :
    • x**y : 次方
    • x*y : 乘法
    • x/y : 除法
    • x+y :
    • x-y :
    • x%y :
  • 2、字符串操作符
    • 只有一个,而且不用写出来,用于实现字符串连接
  • 3、赋值操作符
    • =
    • +=
    • -=
    • *=
    • /=
    • %=
    • ^=
    • **=
    • ++
    • --

      需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,就以/[=]/替代

  • 4、布尔值

    awk中,任何非0值或非空字符串都为真,反之为假

  • 5、比较操作符
    • x<y
    • x<=y
    • x>y
    • x>=y
    • x==y
    • x!=y
    • x~y
    • x!~y
  • 6、逻辑操作符
    • &&
    • ||
    • !
  • 7、函数调用
    • `func_name(argu1,argu2,....)
  • 8、条件表达式
    • selector?if-true-expression:if-false-expression
      • awk -F: ‘{$3>=1000?usertype=“Common user”:usertype=“Sysadmin or sysUser”;printf “%15s:%-s\n",$1,usertype}’ /etc/passwd
awk的数组
1、定义数组的注意事项
  • 1、可使用任意字符串,字符串要使用双引号
  • 2、如果某数组元素事先不存在,在引用时awk会自动创建此元素,并将其初始化为空串
  • 3、要遍历数组中的每个元素,要使用for循环

    • for(var in array){statement1,.....}

        注意:var用于引用数组时,是引用的下标,而不是元素值
      定义数组的格式
  • awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print week["mon"]}'
示例:
  • 统计netstat -tan中各状态的次数
    • netstat -tan | awk '/^tcp>/{state[$NF]++}END{for(i in state) {print i,state[i]}}’
      • 每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引
  • 统计www服务的访问日志中IP数量
    • awk ‘{ip[$1]++} END {for (i in ip) {print i,ip[i]}}’ /var/log/httpd/access_log
  • 统计/etc/fstab文件中每个文件系统类型出现的次数

    • awk '/^UUID/{filesystem[$3]++}END{for (i in filesystem) {print i,filesystem[i]}}' /etc/fstab
  • 统计指定文件中单词的出现次数

    • awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab
  • 统计出/etc/passwd文件中shell的种类和个数

    • awk -F: '{shell[$NF]++}END{for(A in shell){print A,shell[A]}}' /etc/passwd
    重点解析一下这条命令:
      首先,shell[$NF]++这个语句。其中的$NF所代表的是一个字符串,即shell的类型。也就是说在这个数组中的元素名称是shell的名称。而后面的++是对这个数组进行赋值。因为在/etc/passwd 这个文件中的shell类型只有两种,即/bin/bash和/sbin/nologin。也就是说这个数组就只有两个元素,并且它的值是不断被更新的。其次,语句for(A in shell)是设定了A是数组shell中的坐标变量,即是A是元素的名称,shell[A]是数组的值。
删除数组变量
  • delete array[index]
awk的内置函数
  • split(string, array [, fieldsep [, seps ] ])

    • 功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列;
    • 示例:

        netstat -tn | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count)print i,count[i]}'
        netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
  • length([string])

    • 功能:返回string字串中字符的个数
  • substr(string, start [, length])
    • 功能:取string字符串中的子串,从start开始,取length个;start从1开始计数
  • system(command)
    • 功能:执行系统command并将结果返回至awk命令
  • systime()
    • 功能:取系统当前时间
  • tolower(s)
    • 功能:将s中的所有字母转为小写
  • toupper(s)
    • 功能:将s中的所有字母转为大写
番外篇!!!!
    Linux Web服务器网站故障分析常用的命令

    系统连接状态篇:
    1.查看TCP连接状态
    netstat -nat |awk ‘{print $6}’|sort|uniq -c|sort -rn

    netstat -n | awk ‘/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}’ 或
    netstat -n | awk ‘/^tcp/ {++state[$NF]}; END {for(key in state) print key,"\t",state[key]}’
    netstat -n | awk ‘/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"t",arr[k]}’

    netstat -n |awk ‘/^tcp/ {print $NF}’|sort|uniq -c|sort -rn

    netstat -ant | awk ‘{print $NF}’ | grep -v ‘[a-z]‘ | sort | uniq -c



    2.查找请求数请20个IP(常用于查找攻来源):

    netstat -anlp|grep 80|grep tcp|awk ‘{print $5}’|awk -F: ‘{print $1}’|sort|uniq -c|sort -nr|head -n20

    netstat -ant |awk ‘/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}’ |sort -rn|head -n20

    3.用tcpdump嗅探80端口的访问看看谁最高

    tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." ‘{print $1"."$2"."$3"."$4}’ | sort | uniq -c | sort -nr |head -20

    4.查找较多time_wait连接

    netstat -n|grep TIME_WAIT|awk ‘{print $5}’|sort|uniq -c|sort -rn|head -n20

    5.找查较多的SYN连接

    netstat -an | grep SYN | awk ‘{print $5}’ | awk -F: ‘{print $1}’ | sort | uniq -c | sort -nr | more

    6.根据端口列进程

    netstat -ntlp | grep 80 | awk ‘{print $7}’ | cut -d/ -f1
    netstat -tnlp | awk '/22/{split($NF,port,"/");d[port[1]]++}END{for(i in d)print i}'



    网站日志分析篇1(Apache):

    1.获得访问前10位的ip地址

    cat access.log|awk ‘{print $1}’|sort|uniq -c|sort -nr|head -10
    cat access.log|awk ‘{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}’

    2.访问次数最多的文件或页面,取前20

    cat access.log|awk ‘{print $11}’|sort|uniq -c|sort -nr|head -20

    3.列出传输最大的几个exe文件(分析下载站的时候常用)

    cat access.log |awk ‘($7~/.exe/){print $10 " " $1 " " $4 " " $7}’|sort -nr|head -20

    4.列出输出大于200000byte(约200kb)的exe文件以及对应文件发生次数

    cat access.log |awk ‘($10 > 200000 && $7~/.exe/){print $7}’|sort -n|uniq -c|sort -nr|head -100

    5.如果日志最后一列记录的是页面文件传输时间,则有列出到客户端最耗时的页面

    cat access.log |awk ‘($7~/.php/){print $NF " " $1 " " $4 " " $7}’|sort -nr|head -100

    6.列出最最耗时的页面(超过60秒的)的以及对应页面发生次数

    cat access.log |awk ‘($NF > 60 && $7~/.php/){print $7}’|sort -n|uniq -c|sort -nr|head -100

    7.列出传输时间超过 30 秒的文件

    cat access.log |awk ‘($NF > 30){print $7}’|sort -n|uniq -c|sort -nr|head -20

    8.统计网站流量(G)

    cat access.log |awk ‘{sum+=$10} END {print sum/1024/1024/1024}’

    9.统计404的连接

    awk ‘($9 ~/404/)’ access.log | awk ‘{print $9,$7}’ | sort

    10. 统计http status

    cat access.log |awk ‘{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}'
    cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn

    10.蜘蛛分析,查看是哪些蜘蛛在抓取内容。

    /usr/sbin/tcpdump -i eth0 -l -s 0 -w - dst port 80 | strings | grep -i user-agent | grep -i -E 'bot|crawler|slurp|spider'

    网站日分析2(Squid篇)按域统计流量

    zcat squid_access.log.tar.gz| awk '{print $10,$7}' |awk 'BEGIN{FS="[ /]"}{trfc[$4]+=$1}END{for(domain in trfc){printf "%st%dn",domain,trfc[domain]}}'

    数据库篇
    1.查看数据库执行的sql

    /usr/sbin/tcpdump -i eth0 -s 0 -l -w - dst port 3306 | strings | egrep -i 'SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL'

    系统Debug分析篇
    1.调试命令
    strace -p pid
    2.跟踪指定进程的PID
    gdb -p pid
(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------