3.9. 9 三剑客之awk

3.9.1. 概念

AWK:报告生成器,格式化文本输出工具

awk [options] 'script' file1,file2...
awk [options] 'PATTERN {action}' file1,file2
  • 处理机制:一次从文件中读取出来一行,按照特定分隔符对其进行切片(默认空格)

  • 步骤:

* 读( Read ):AWK 从输入流(文件、管道或者标准输入)中读入一行然后将其存入内存中。
* 执行(Execute):对于每一行输入,所有的 AWK 命令按顺执行。 默认情况下,AWK 命令是针对于每一行输入,但是我们可以将其限制在指定的模式中。
* 重复(Repeate):一直重复上述两个过程直到文件结束。
  • 程序结构:

  • 开始块(BEGIN BLOCK):

语法:
BEGIN{awk-commands}
开始块就是awk程序启动时执行的代码部分(在处理输入流之前执行),并且在整个过程中只执行一次;一般情况下,我们在开始块中初始化一些变量。BEGIN是awk的关键字,因此必须要大写。【注:开始块部分是可选,即你的awk程序可以没有开始块部分】
  • 主体块(Body Block):

语法:
/pattern/{awk-commands}
针对每一个输入的行都会执行一次主体部分的命令,默认情况下,对于输入的每一行,awk都会执行主体部分的命令,但是我可以使用/pattern/限制其在指定模式下。
  • 结束块(END BLOCK):

语法:
END{awk-commands}
结束块是awk程序结束时执行的代码(在处理完输入流之后执行),END也是awk的关键字,必须大写,与开始块类似,结束块也是可选的。
awk 脚本的结构如下:
awk 'BEGIN{ print "start" } pattern { commands } END{ print "end" }' file


$ cat users.txt |wc -l
6

# 统计文件行数
$ awk 'BEGIN {i=0} {i++} END {print i}' users.txt
6


# 在文本中加上头和尾部输出
$ echo -e "line1\nline2\nline3"| awk 'BEGIN {print "Start"} {print } END {print "End"}'
$ echo -e "line1\nline2\nline3"| awk 'BEGIN {print "Start"} {print $0} END {print "End"}'
Start
line1
line2
line3
End

3.9.2. awk输出

  1. print 使用格式

print item1,item2...

要点: * 1.各字段之间逗号隔开,输出时以空白字符分割;

  • 2.输出的字段可以为字符串或数值,当前记录的字段(如$1)、变量或awk的表达式;数值先回转换成字符串然后输出

  • 3.print命令后面的item可以省略,此时其功能相当于print $0,如果想输出空白,可以使用print ""

eg:

awk -F: '{print $1,$NF}' /etc/passwd|column -t

tail -1 /etc/passwd|awk -F: 'BEGIN{OFS="#"}{print “hello”$1,$2}'

# print能够接受参数,参数以逗号隔开,在打印参数时则以空格作为参数之间的分隔符。
$ echo | awk '{var="hujianli";var2="hujianli2";var3="hujianli3"; print var,var2,var3;}'
hujianli hujianli2 hujianli3

# 拼接的使用方法如下:
$ echo | awk '{var="hujianli";var2="hujianli2";var3="hujianli3"; print var "-" var2 "-"var3;}'
hujianli-hujianli2-hujianli3

{ } 就像一个循环体,对文件中的每一行进行迭代

2.printf

printf命令的使用格式:

printf <format> item1,item2...

要点: * 1.其与print命令最大区别,printf 需要指定format,format必须给出

  • 2.format用于指定后面的每个item输出格式

  • 3.printf 语句不会自动打印换行字符:

format格式的指示符都以%开头,后跟一个字符:

%c:显示ascall码
%d:%i:十进制整数
%e,%E:科学计数法
%f:浮点数
%s:字符串
%u:无符号整数
%%:显示%自身

修饰符:
#[.#]:第一个#控制显示的宽度:第二个#表示小数点后的精度:

%3.1f

-:左对齐
+:显示数组符号

eg:

awk -F: '{printf "Username:%-15s   ,Uid:%d\n",$1,$3}' /etc/passwd

1.awk 可以使用的一些特殊变量。

  NR :表示记录编号,当 awk 将行作为记录时,该变量相当于当前行号。
  NF :表示字段数量,在处理当前记录时,相当于字段数量。默认的字段分隔符是空格。
  $0 :该变量包含当前记录的文本内容。
  $1 :该变量包含第一个字段的文本内容。
  $2 :该变量包含第二个字段的文本内容



$ echo -e "line1 f2 f3\nline f4 f5\nline3 f6 f7"|\
awk '{print "Line number:"NR ",number of fields:"NF,"$0="$0,"$1="$1,"$2="$2,"$3="$3}'

Line number:1,number of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3
Line number:2,number of fields:3 $0=line f4 f5 $1=line $2=f4 $3=f5
Line number:3,number of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7



$ seq 5 | awk 'BEGIN { sum=0; print "Summation:" }
> { print $1"+"; sum+=$1 } END { print "=="; print sum }'
Summation:
1+
2+
3+
4+
5+
==
15

2.awk 使用外部变量

$ var=hujianli
$ echo | awk -v VAR=$var '{print VAR}'
hujianli

$ var1="hujianli01";var2="hujianli02"
$ echo | awk '{print v1,v2}' v1=$var1 v2=$var2
hujianli01 hujianli02

3,用 getline 读取行

$ seq 5| awk 'BEGIN { getline; print "Read ahead first line", $0 }''{print $0}'
Read ahead first line 1
2
3
4
5

4.使用过了模式对awk处理的行进行过滤

我们可以为需要处理的行指定一些条件:
$ awk 'NR < 5' #  行号小于5 的行
$ awk 'NR==1,NR==4' #  行号在1 到5 之间的行
$ awk '/linux/' #  包含模式为linux 的行(可以用正则表达式来指定模式)
$ awk '!/linux/' #  不包含模式为linux

5.设置字段分隔符

设置字段分隔符 默认的字段分隔符是空格。我们也可以用选项 -F 指定不同的分隔符:

$ awk -F: '{ print $NF }' /etc/passwd
或者
awk 'BEGIN { FS=":" } { print $NF }' /etc/passwd

6.从awk中读取命令输出

从 awk 中读取命令输出
awk 可以调用命令并读取输出。把命令放入引号中,然后利用管道将命令输出传入 getline :
"command" | getline output ;

下面的代码从/etc/passwd文件中读入一行,然后显示出用户登录名及其主目录。在 BEGIN 语
句块中将字段分隔符设置为 : ,在主语句块中调用了 grep 。

$ awk 'BEGIN {FS=":"} { "grep root /etc/passwd" | getline; print $1,$6 }'
root /root

3.9.3. awk变量

  • awk内置变量之记录变量:

+ FS:field separator,输入字段分隔符(默认空白)
+ OFS:output field separator,输出字段分隔符
+ RS:Record separator:输入文本换行符(默认回车)

+ ORS:输出文本换行符
  • awk内置变量之数据变量

+ NR:the number of input records,awk命令所处理的文件的行数,如果有多个文件,这个数目会将处理的多个文件计数
+ NF:number of field,当前记录的field个数

{print NF},{print $NF}


* ARGV:数组,保存命令行本身这个字符串,

* ARGC:awk命令的参数个数

* FILENAME:awk命令处理的文件名称

* ENVIRON:当前shell环境变量及其值的关联数组

awk 'BEGIN{print ENVIRON["PATH"]}'
  • 自定义变量 -v var=value

变量名区分大小写

awk -v test="abc" 'BEGIN{print test}'

awk 'BEGIN{var="name";print var}'

3.9.4. 操作符

  • 算术运算

+,-,*,/,^,%

awk 'BEGIN{a=5;b=3;print "a + b =",a+b}'

  • 字符串操作

无符号操作符,表示字符串连接
awk 'BEGIN { str1="Hello,"; str2="World"; str3 = str1 str2; print str3 }'
  • 赋值操作符

=,+=,-=,*=,/=,%=,^=
awk 'BEGIN{a=5;b=6;if(a == b) print "a == b";else print "$a!=b"}'
awk -F: '{sum+=$3}END{print sum}' /etc/passwd
  • 比较操作符:

* \>,>=,<,<=,!=,==
  • 模式匹配符:

* ~:是否匹配
* !~:是否不匹配
awk -F: '$1~"root"{print $0}' /etc/passwd
  • 逻辑操作符:

* && 、 || 、 !
awk 'BEGIN{a=6;if(a > 0 && a <= 6) print "true";else print "false"}'
  • 函数调用:

    * function_name(argu1,augu2)
* 条件表达式(三元运算):
    * selection?if-true-expresssion:if-false-expression

awk -F: '{$3>=100?usertype="common user":usertype="sysadmin";printf "%15s:%s\n",$1,usertype}' /etc/passwd

3.9.5. Pattern

  • empty:空模式,匹配每一行

  • /regular expression/:仅处理能被此处模式匹配到的行

  • relational expression:关系表达式,结果为“真”有“假”,结果为“真”才会被处理,注意:使用模式需要使用双斜线括起来

    • 真:结果为非0值,非空字符串

awk -F: '$3>100{print $1,$3}' /etc/passwd

awk -F: '$NF=="/bin/bash"{printf "%15s,%s\n",$NF,$1}' /etc/passwd

awk -F: '$NF~/bash$/{printf "%15s,%s\n",$NF,$1}' /etc/passwd

df -Th|awk '/^\/dev/{print}'
  • line ranges:行范围,制定startline,endline

awk -F: '/10/,/20/{print $1}' /etc/passwd
awk -F: '(NR>2&&NR<=10){print $1}' /etc/passwd
  • BEGIN/END模式

* BEGIN{}:仅在开始处理中的文本之前执行一次
* END{}:仅在文本处理完成之后执行一次
    awk -F: 'BEGIN{print "username     uid\n--------------------"}{printf "%-15s:%d\n",$1,$3}END{print "-----------------\ne
nd"}' /etc/passwd

3.9.6. 常用action

  • Expression

  • Control statements

    • if/while

  • Compound statements

  • input statements

  • output statements

控制语句

  • if(condition) {statements}

  • if(condition) {statments} [else {statments}]

awk -F: '{if($3>100) print $1,$3}' /etc/passwd

awk -F: '{if($3>100) {printf "Common user:%-15s\n",$1} else {printf "sysadmin user:%-15s\n",$1}}' /etc/passwd

awk -F: '{if($NF=="/bin/bash") print $1,$NF}' /etc/passwd

awk -F: '{if($NF>7) print}' /etc/fstab
  • while(conditon) {statments}

  • 条件为“真”,进入循环,条件为“假”,退出循环

  • 使用场景:对一行内的多个字段逐一类似处理时使用,对数组内的各元素逐一进行处理时使用

awk '/^[[:space:]]*if/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/init.d/functions

awk '/^[[:space:]]*if/{i=1;while(i<NF) {if(length($i)>7) {print $i,length($i)};i++}}' /etc/init.d/functions
  • do {statements} while(condition)

    • 意义:至少执行一次循环体

  • for(expr1;expr2;expr3) {statements}

    • 语法:for(variable assignment;condition;iteration process) {for-body}

    • 特殊用法:能够遍历数组中的元素,for (var in array) {for-body}

awk '/^[[:space:]]*if/{for(i=1;i<NF;i++) {print $i,length($i)}}' /etc/init.d/functions

awk '/^[[:space:]]*if/{for(i=1;i<NF;i++) {if(length($i)>7) print $i,length($i)}}' /etc/init.d/functions
  • break

  • continue

  • delete array[index]

  • switch语句

    • 语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 VALUE2 or /EXGEXP2/: statement;…;default: statement}

3.9.7. array

  • 关联数组:

  • array[index-expression]

  • index-pression:

    • 任意字符串

    • 如果某数组元素事先不存在,引用时候,awk自动创建此元素,并将其值初始化为空串,若要判断数组中是否存在某元素,需要使用index in array格式进行

awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}'
  • 遍历数组使用for循环

    • for(var in array) {do-body}

awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) print weekdays[i]}'
  • 注意:var会遍历array的每个索引:

netstat -tan|awk '/^tcp/{state[$NF]++}END{for(i in state) print i,state[i]}'

awk '{ips[$1]++}END{for(i in ips){printf "%-5d,%s\n",ips[i],i}}' /var/log/httpd/access_log-20180916 |sort -k1 -nr

3.9.8. 函数

  • 内置函数

    • 数值处理:

rand():返回0和1之间的一个随机数

awk 'BEGIN{print rand()}'
  • 字符串处理:

    length([s]):返回制定字符串的长度

    sub(r,s,[t]):以r表示的模式来查找t所表示的字符串中匹配到的内容,并将其第一次出现替换为s所表示的那日

  • eg

awk '/Tom/' file               # 打印匹配到得行
awk '/^Tom/{print $1}'         # 匹配Tom开头的行 打印第一个字段
awk '$1 !~ /ly$/'              # 显示所有第一个字段不是以ly结尾的行
awk '$3 <40'                   # 如果第三个字段值小于40才打印
awk '$4==90{print $5}'         # 取出第四列等于90的第五列
awk '/^(no|so)/' test          # 打印所有以模式no或so开头的行
awk '$3 * $4 > 500'            # 算术运算(第三个字段和第四个字段乘积大于500则显示)
awk '{print NR" "$0}'          # 加行号
awk '/tom/,/suz/'              # 打印tom到suz之间的行
awk '{a+=$1}END{print a}'      # 列求和
awk 'sum+=$1{print sum}'       # 将$1的值叠加后赋给sum
awk '{a+=$1}END{print a/NR}'   # 列求平均值
awk '!s[$1 $3]++' file         # 根据第一列和第三列过滤重复行
awk -F'[ :\t]' '{print $1,$2}'           # 以空格、:、制表符Tab为分隔符
awk '{print "'"$a"'","'"$b"'"}'          # 引用外部变量
awk '{if(NR==52){print;exit}}'           # 显示第52行
awk '/关键字/{a=NR+2}a==NR {print}'      # 取关键字下第几行
awk 'gsub(/liu/,"aaaa",$1){print $0}'    # 只打印匹配替换后的行
ll | awk -F'[ ]+|[ ][ ]+' '/^$/{print $8}'             # 提取时间,空格不固定
awk '{$1="";$2="";$3="";print}'                        # 去掉前三列
echo aada:aba|awk '/d/||/b/{print}'                    # 匹配两内容之一
echo aada:abaa|awk -F: '$1~/d/||$2~/b/{print}'         # 关键列匹配两内容之一
echo Ma asdas|awk '$1~/^[a-Z][a-Z]$/{print }'          # 第一个域匹配正则
echo aada:aaba|awk '/d/&&/b/{print}'                   # 同时匹配两条件
awk 'length($1)=="4"{print $1}'                        # 字符串位数
awk '{if($2>3){system ("touch "$1)}}'                  # 执行系统命令
awk '{sub(/Mac/,"Macintosh",$0);print}'                # 用Macintosh替换Mac
awk '{gsub(/Mac/,"MacIntosh",$1); print}'              # 第一个域内用Macintosh替换Mac
awk -F '' '{ for(i=1;i<NF+1;i++)a+=$i  ;print a}'      # 多位数算出其每位数的总和.比如 1234, 得到 10
awk '{ i=$1%10;if ( i == 0 ) {print i}}'               # 判断$1是否整除(awk中定义变量引用时不能带 $ )
awk 'BEGIN{a=0}{if ($1>a) a=$1 fi}END{print a}'        # 列求最大值  设定一个变量开始为0,遇到比该数大的值,就赋值给该变量,直到结束
awk 'BEGIN{a=11111}{if ($1<a) a=$1 fi}END{print a}'    # 求最小值
awk '{if(A)print;A=0}/regexp/{A=1}'                    # 查找字符串并将匹配行的下一行显示出来,但并不显示匹配行
awk '/regexp/{print A}{A=$0}'                          # 查找字符串并将匹配行的上一行显示出来,但并不显示匹配行
awk '{if(!/mysql/)gsub(/1/,"a");print $0}'             # 将1替换成a,并且只在行中未出现字串mysql的情况下替换
awk 'BEGIN{srand();fr=int(100*rand());print fr;}'      # 获取随机数
awk '{if(NR==3)F=1}{if(F){i++;if(i%7==1)print}}'       # 从第3行开始,每7行显示一次
awk '{if(NF<1){print i;i=0} else {i++;print $0}}'      # 显示空行分割各段的行数
echo +null:null  |awk -F: '$1!~"^+"&&$2!="null"{print $0}'       # 关键列同时匹配
awk -v RS=@ 'NF{for(i=1;i<=NF;i++)if($i) printf $i;print ""}'    # 指定记录分隔符
awk '{b[$1]=b[$1]$2}END{for(i in b){print i,b[i]}}'              # 列叠加
awk '{ i=($1%100);if ( $i >= 0 ) {print $0,$i}}'                 # 求余数
awk '{b=a;a=$1; if(NR>1){print a-b}}'                            # 当前行减上一行
awk '{a[NR]=$1}END{for (i=1;i<=NR;i++){print a[i]-a[i-1]}}'      # 当前行减上一行
awk -F: '{name[x++]=$1};END{for(i=0;i<NR;i++)print i,name[i]}'   # END只打印最后的结果,END块里面处理数组内容
awk '{sum2+=$2;count=count+1}END{print sum2,sum2/count}'         # $2的总和  $2总和除个数(平均值)
awk -v a=0 -F 'B' '{for (i=1;i<NF;i++){ a=a+length($i)+1;print a  }}'     # 打印所以B的所在位置
awk 'BEGIN{ "date" | getline d; split(d,mon) ; print mon[2]}' file        # 将date值赋给d,并将d设置为数组mon,打印mon数组中第2个元素
awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'      # 截取字符串(substr使用)
awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'      # 匹配字符串(index使用)
awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'    # 正则表达式匹配查找(match使用)
awk '{for(i=1;i<=4;i++)printf $i""FS; for(y=10;y<=13;y++)  printf $y""FS;print ""}'        # 打印前4列和后4列
awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"x"n"="i*n" ";print ""}}'                # 乘法口诀
awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'             # 字符串分割(split使用)
awk '{if (system ("grep "$2" tmp/* > /dev/null 2>&1") == 0 ) {print $1,"Y"} else {print $1,"N"} }' a            # 执行系统命令判断返回状态
awk  '{for(i=1;i<=NF;i++) a[i,NR]=$i}END{for(i=1;i<=NF;i++) {for(j=1;j<=NR;j++) printf a[i,j] " ";print ""}}'   # 将多行转多列
netstat -an|awk -v A=$IP -v B=$PORT 'BEGIN{print "Clients\tGuest_ip"}$4~A":"B{split($5,ip,":");a[ip[1]]++}END{for(i in a)print a[i]"\t"i|"sort -nr"}'    # 统计IP连接个数
cat 1.txt|awk -F" # " '{print "insert into user (user,password,email)values(""'\''"$1"'\'\,'""'\''"$2"'\'\,'""'\''"$3"'\'\)\;'"}' >>insert_1.txt     # 处理sql语句
awk 'BEGIN{printf "what is your name?";getline name < "/dev/tty" } $1 ~name {print "FOUND" name " on line ", NR "."} END{print "see you," name "."}' file  # 两文件匹

exercises:

* 统计/etc/fstab文件中每个单词出现的次数,并按从大到小排序
awk '{for(i=1;i<=NF;i++){words[$i]++}}END{for(key in words)print key,words[key]}' /etc/fstab|sort -k2 -nr

awk '{ips[$1]++}END{for(i in ips) print i,ips[i]}' access_nginx.log |column -t|sort -k2 -nr

* 统计/etc/fstab每个文件系统类型出现的次数
awk '!/^#/&&!/^$/{dev[$3]++}END{for(i in dev) print i,dev[i]}' /etc/fstab

* ping一个域名,输出ping此刻的时间
ping baidu.com|awk '{print $0" "strftime("%Y-%m-%d %H:%M:%S")}'

* 利用netstat监控服务是否正常监听
netstat -lntup|awk 'NR>2{if($4 ~/.*:22/) print $0"yes";exit 0}'

* 统计web服务器日志状态码
awk '$9~"[0-9]"{stat[$9]++}END{for(i in stat) print i,stat[i]}' access_log

3.9.9. awk判断

awk '{print ($1>$2)?"第一排"$1:"第二排"$2}'      # 条件判断 括号代表if语句判断 "?"代表then ":"代表else
awk '{max=($1>$2)? $1 : $2; print max}'          # 条件判断 如果$1大于$2,max值为为$1,否则为$2
awk '{if ( $6 > 50) print $1 " Too high" ;\
else print "Range is OK"}' file
awk '{if ( $6 > 50) { count++;print $3 } \
else { x+5; print $2 } }' fil

3.9.10. awk循环

awk '{i = 1; while ( i <= NF ) { print NF, $i ; i++ } }' file
awk '{ for ( i = 1; i <= NF; i++ ) print NF,$i }' fi

3.9.11. awk练习题

wang     4
cui      3
zhao     4
liu      3
liu      3
chang    5
li       2

1 通过第一个域找出字符长度为4的
2 当第二列值大于3时,创建空白文件,文件名为当前行第一个域$1 (touch $1)
3 将文档中 liu 字符串替换为 hong
4 求第二列的和
5 求第二列的平均值
6 求第二列中的最大值
7 将第一列过滤重复后,列出每一项,每一项的出现次数,每一项的大小总和

1、字符串长度
    awk 'length($1)=="4"{print $1}'
2、执行系统命令
    awk '{if($2>3){system ("touch "$1)}}'
3、gsub(/r/,"s",域) 在指定域(默认$0)中用s替代r  (sed 's///g')
    awk '{gsub(/liu/,"hong",$1);print $0}' a.txt
4、列求和
    awk '{a+=$2}END{print a}'
5、列求平均值
    awk '{a+=$2}END{print a/NR}'
    awk '{a+=$2;b++}END{print a,a/b}'
6、列求最大值
    awk 'BEGIN{a=0}{if($2>a) a=$2 }END{print a}'
7、将第一列过滤重复列出每一项,每一项的出现次数,每一项的大小总和
    awk '{a[$1]++;b[$1]+=$2}END{for(i in a){print i,a[i],b[i]}}\
# awk
而awk则是基于列的文本处理工具,它的工作方式是按行读取文本并视为一条记录,每条记录以字段分割成若干字段,然后输出各字段的值。

每个非空白的部分叫做“域”,从左到右依次是第一个域、第二个域,等等。$1$2分别用于表示域,$0则表示全部域。

[root@localhost ~]# cat awk.txt
hujianli.wang        male    30   021-1111111
jianli.hu            Female  25   021-222222
jack.chen            Male    35   021-333333
lily.gong           Female   20   021-4444444  shanghai

## 打印$1和$4的内容
[root@localhost ~]# awk '{print $1,$4}' awk.txt
hujianli.wang 021-1111111
jianli.hu 021-222222
jack.chen 021-333333
lily.gong 021-4444444

## 打印全部内容
[root@localhost ~]# awk '{print $0}' awk.txt
hujianli.wang        male    30   021-1111111
jianli.hu            Female  25   021-222222
jack.chen            Male    35   021-333333
lily.gong           Female   20   021-4444444  shanghai

## 通过-F指定分隔符. 默认分隔符空白字符或者空格
[root@localhost ~]# awk -F. '{print $1,$2}' awk.txt
hujianli wang        male    30   021-1111111
jianli hu            Female  25   021-222222
jack chen            Male    35   021-333333
lily gong           Female   20   021-4444444  shanghai


## 内部变量NF,列数
[root@localhost ~]# awk '{print NF}' awk.txt
4
4
4
5

[root@localhost ~]# awk -F. '{print NF}' awk.txt
2
2
2
2
[root@localhost ~]# cat awk.txt
hujianli.wang        male    30   021-1111111
jianli.hu            Female  25   021-222222
jack.chen            Male    35   021-333333
lily.gong           Female   20   021-4444444  shanghai


## 打印最后1列的内容
[root@localhost ~]# awk '{print $NF}' awk.txt
021-1111111
021-222222
021-333333
shanghai

## 打印倒数第2列内容
[root@localhost ~]# awk '{print $(NF-1)}' awk.txt
30
25
35
021-4444444


## 截取字符串
可以使用substr()函数对指定域截取字符串
函数的用法:
substr( 指定域, 第一个开始字符的位置, 第二个结束的位置) # 其中第二个结束的位置可以为空,这样默认输出到该域的最后一个字符

[root@localhost ~]# cat awk.txt
hujianli.wang        male    30   021-1111111
jianli.hu            Female  25   021-222222
jack.chen            Male    35   021-333333
lily.gong           Female   20   021-4444444  shanghai

[root@localhost ~]# cat awk.txt | awk '{print substr($1,2)}'
ujianli.wang
ianli.hu
ack.chen
ily.gong


## 确定字符串的长度
使用内部变量length可以确定字符串的长度
[root@localhost ~]# cat awk.txt | awk '{print length}'
45
38
44
50

## 使用awk求列和
求第3个域   年龄总和
[root@localhost ~]# cat awk.txt | awk 'BEGIN{total=0}{total+=$3}END{print total}'
110

求平均年龄,$NR表示行数总和
[root@localhost ~]# cat awk.txt | awk 'BEGIN{total=0}{total+=$3}END{print total/NR}'
27.5