• awk--动作(action)


    摘要

    awk--简述中我们讲到awk是由pattern-action组合而成的,关于pattern我们已经awk--模式(pattern)在讲述,接下来就来看下awk的action.

     

    动作是什么

    我们同样举在awk--模式(pattern)我们所使用的例子:

    //打印当前目录下面,大小大于1K(1024)的文件或目录名称
    ls -l | awk 'NR > 1 && $5 > 1024 {print $9}'
    

    加粗字体部分即为动作,本处的动作是打印被awk分割后的第9个字段,

    所以可以认为在awk 中执行主要是由模式匹配先匹配,匹配正确后再进行执行即action(动作).

     

    有什么动作

    awk的action主要包含两类:
    1.常规的表达式(包含设置常量,变量,赋值, 函数调用(包含 print,printf 和 自定义函数))
    2.流程(比如if while for等)

     

    动作的使用

    常量和变量

    • awk的常量/变量类型

    awk只有两种数据类型:

    1)字符串

    2)数值

    相互转换

    字符串指的是被双引号(“”)包裹的串,字符串和数值可以按照情况自己转换.

    需要强行转换的时候可以使用:

    1)字符串->数值: string+0(因为0对数组没有影响- -),比如 “1” + 0

    2)数值->字符串: number””即可,比如 1””;

    支持运算

    1)对于字符串只有一种运算符:拼接

    比如:
    awk -F "||" '{print $1":"$2}' worker.txt
    输出:
    1:Jack
    2:Lip
    

    2)对于数值而言:awk支持的常规C的运算符操作,如:++,--..等

    • 内建变量

    (1)ARGC/ARGV

    含义:输入行参数的个数/数组

    例子:略

    (2)FILENAME

    含义:当前输入行的文件名称

    例子:在存在多个文件时,可以进行对不同的输入行进行区分,

    awk '{ if(FILENAME=="worker.txt")  { print 1 }  else{ print 2} }' worker.txt  countries 
    

     

     (3)NR

    含义:当前输入行的序号(不断累加)

    例子:

    awk '{printf("%s  ",NR)} END{printf("
    ")}' worker.txt countries
    输出:1  2  3  4  5  6  7  8  9  10  11  12  13
    

    (4)FNR

    含义:当前输入行对输入内容的序号(每个输入都会被独立的排列序号)

    例子:

    awk '{printf("%s  ",FNR)} END{printf("
    ")}' worker.txt countries
    输出:1  2  1  2  3  4  5  6  7  8  9  10  11
    

    注意:存在多个文件时,NR是不断累加的,因此对于仅有两个输入的时候,只需要根据NR,FNR就可以区别输入源了,

    比如(2)FILENAME的例子就可以修改为:

    awk 'NR==FNR{ print 1} NR > FNR{ print 2 }' worker.txt country 
    

    (5)NF

    含义:当前输入行的字段总数(可以理解为:ALineInput.splite(`FS`).count())

    例子:

    awk -F "||" '{printf("当前输入行的字段数:%d,输入行:%s
    ",NF,$0)}' worker.txt
    输出:
    当前输入行的字段数:5,输入行:1||Jack||25||man||Chinese,FuJian 
    

    (6)FS/OFS

    含义:设置输入/输出的分隔符

    例子:

    awk 'BEGIN{FS="||";printf("%3s
    ","ID")} {printf("%.3d
    ",$1)}'  worker.txt
    或
    awk –F  "||"  '{printf("%3s
    ","ID")} {printf("%.3d
    ",$1)}'  worker.txt
    

    (7)RS/ORS

    含义:输入/输出记录的分隔符

    例子:略,默认RS=ORS= " "

    (8)OFMT

    含义:数值的输出格式

    例子:略

    (9)RLENGTH/RSTART

    含义:awk内置函数match(s,r)(匹配函数)的返回值,其中RLENGTH(rightlength)表示匹配长度,RSTART表示匹配r的输入行s的起始位置

    例子:

    //匹配输入行是否存在字符串"Chinese"
    awk -F "||" '{match($0,"Chinese");if(RLENGTH > 1) printf(""Chinese" can match in "%s",RSTART:%d,RLENGTH:%d
    ",$0,RSTART,RLENGTH)}' worker.txt
    
    输出:
    "Chinese" can match in "1||Jack||25||man||Chinese,FuJian",RSTART:19,RLENGTH:7
    可见RSTART的计数是由1开始的
    

    (10)SUBSEP

    含义:下标分割符

    例子:略,默认SUBSET="34"

    • 自定义变量

    用户子自定义的变量的首字母不能是数字,需要在命令行前面设置变量可以使用awk –v key=value的方式,

    比如:

    //设置在动作中使用的自定义变量current_path
    awk -v current_path = `pwd` '{print current_path}'  input
    

    也可以采用如下方式:

    var="var!"
    awk 'BEGIN{print "'$var'"}' empty.txt
    输出为:
    var!
    

    不过貌似变量var的值不能包含空格(环境:Ubuntu14.04,bash).

    数组

    • 简介

    awk提供了一维数组,用于存放字符串与数值.数组和数组元素都不需要事先声明,也不需要说明数组中有多少个元素.

    就像变量一样,当被提及时数组元素就会被创建,数组元素的默认初始值为0或者空字符串””.

    awk的下标采用字符串,因此也被成为关联数组(类似与hash或map).

    比如:

    awk '/Asia/ {pop["Asia"] += $3} END {print "Asia populate:", pop["Asia"]}' countries
    输出:
    Asia populate: 2173
    
    • 遍历数组

    在awk中遍历数组可以有两种方式

    方式1) for(i=0; i< **; i++){}

    方式2) for(val in array) {} (即foreach)

    方式1的缺陷是我们需要知道当前数组的个数,因此在awk中更适用于方式2.

    注意:如果需要判断元素是否存在在数组话,可以采用下面的方法:

    if(val in array)

    比如:

    if (“Asia” in pop)

    如果采用if (array[variable] != **)  且**为空的那么该if返回true,

    原因是在进行array[variable]的时候,如果awk判断下标为variable的元素不存在时就会默认创建一个空字符串.

    • 删除数组

    1)删除单个 delete array[val]即可

    2)全部删除 for(val in array) delete array[val]

    • 多维数组

    实际上awk并不提供多维数组,但是因为awk的下标采用的字符串,所以你可以按照你的方式构造多维数组,比如:

    awk '{for(i = 1; i <=3; i++) {for(j=1;j<=3;j++) {pop[i""j]=i*j}}} END{for (data in pop) {print "sub=",data,"data:",pop[data]}}' worker.txt
    
    输出为:
    sub= 11 data: 1
    sub= 12 data: 2
    sub= 13 data: 3
    sub= 21 data: 2
    sub= 22 data: 4
    sub= 23 data: 6
    sub= 31 data: 3
    sub= 32 data: 6
    sub= 33 data: 9
    

    其中pop[i""j]是为了将数值转化为字符串

    函数

    • 内建函数

    1)数值型内建函数

    awk内建算数函数类似于C语言包括:
    sin(x)
    cos(x)
    atan2(y,x)

    rand()
    srand(x)

    exp(x)
    log(x)

    sqrt(x)
    int(x)

    比如:

    awk 'BEGIN{print "sqrt(4) =",sqrt(4)}' empty.txt
    输出:
    sqrt(4) = 2 
    

    2)字符型内建函数

    awk中字符串的内置函数和C的存在略微不同,主要有以下几个:

    (1)sub(r,s) 含义:将$0的最左最长的r,替换成s,返回替换的次数
    sub(r,s,t) 含义:将t的最左最长的r,替换成s,返回替换的次数

    比如:

    awk -F "||" '{sub("man","female",$0);print}' worker.txt
    输出为:
    1||Jack||25||female||Chinese,FuJian
    2||Lip||30||female||American
    

    (2)gsub(r,s)  含义:将输入行中的字符串r替换为s,返回替换发生的次数

    gsub(r,s,t)含义: t为输入行,将t中出现的字符串r替换替换成s
    比如:

    awk '{gsub("man","female"); print $0}' worker.txt
    输出为:
    1||Jack||25||female||Chinese,FuJian
    2||Lip||30||female||American
    
    awk '{gsub("man","female",$0); print $0}' worker.txt
    输出为:
    1||Jack||25||female||Chinese,FuJian
    2||Lip||30||female||American
    

    另外:
    对于一个在sub或gsub执行的替换来说,字符&在s中的任意一次出现都会被替换成r.(即& = r)

    比如:

    awk '{gsub(/a/,""&*&"",$0); print}' worker.txt
    输出为:
    1||J"a*a"ck||25||m"a*a"n||Chinese,FuJi"a*a"n
    2||Lip||30||m"a*a"n||Americ"a*a"n
    即:使用“a*a”替换原本的a
    

    (3)index(s,t)

    含义:返回字符串t在s中第一次出现的位置,如果未找到返回0
    比如:

    awk '{print ""man" index:" index($0,"man")}' worker.txt
    输出为:
    "man" index:14
    "man" index:13
    

    (4)length(s)

    含义:返回字符串s的长度

    比如:

    awk -F "||" '{printf(""%s" length:%d
    ",$2,length($2))}' worker.txt
    输出为:
    "Jack" length:4
    "Lip" length:3
    

    (5)match(s,r)

    含义:测试s中是否包含能被r匹配的字符串,返回s中被匹配的起始位置,并设置内置变量RSTART,RLENGTH

    比如:

    awk -F "||" '{match($0,"Chinese");if(RLENGTH > 1) printf(""Chinese" can match in "%s",RSTART:%d,RLENGTH:%d
    ",$0,RSTART,RLENGTH)}' worker.txt
    输出为:
    "Chinese" can match in "1||Jack||25||man||Chinese,FuJian",RSTART:19,RLENGTH:7
    可见RSTART的计数是由1开始的
    

    (6)split(s,a) 含义:用FS将s分割到数组a中,返回字段的个数
    split(s,a,fs) 含义:用fs将s分割到数组a中,返回字段的个数

    比如:

    awk 'BEGIN { FS="||"} {iAddress = split($5,Address,","); for(i=1;i<=iAddress;i++){ printf("currunt %d Address:%s
    ",i,Address[i])} }' worker.txt
    输出为:
    currunt 1 Address:Chinese
    currunt 2 Address:FuJian
    currunt 1 Address:American
    可见在split中数组存储的顺序为arr[“1”],arr[“2”]....
    

    (7)sprintf(fmt,expr-list)

    含义: 按照格式格式化字符串,返回生成的格式化字符串
    比如:

    awk -F "||" '{print sprintf("id:%d name:%s",$1,$2)}' worker.txt
    输出为:
    id:1 name:Jack
    id:2 name:Lip 
    
    • 自定义函数

    awk中使用自定义函数可以使用function关键字

    比如:

    awk 'BEGIN{print max(1,2) } function max(m,n) { return m > n ? m : n}' empty.txt
    输出:2
    
    awk 'BEGIN{ myprint("hello,world") } function max(m,n) { return m > n ? m : n} function myprint(x){print x}' empty.txt
    输出: hello,world
    

    流程控制

    awk中的流程控制语句用法同C语言类似

    1)if..else..

    比如:

    //区分多个输入的方法(缺点需要知道输入的文件名称)
    awk -F "||| " '{if(FILENAME == "worker.txt") {print "input is worker.txt",$2} else if(FILENAME == "countries") { print "input is countries",$4}}' worker.txt countries
    

    2)for/while/break

    输出

    1)输出到stdout(默认)

    比如:

    awk -F "||" '{print sprintf("id:%d name:%s",$1,$2)}' worker.txt
    输出:
    id:1 name:Jack
    id:2 name:Lip 
    

    2)输出到file

    比如:
    awk -F "||" '{print sprintf("id:%d name:%s",$1,$2) > "test.txt"}' worker.txt
    
    cat test.txt内容为:
    id:1 name:Jack
    id:2 name:Lip
    

    注意:

    在同一个程序中如果存在输出到文件中(如上面的:test.txt),在稍后的流程又需要读取这个文件(例子:test.txt)的话,那么你必须在读取之前先关闭一下文件(将缓存的内容写入到文件中),在读取文件.
    关闭的写法为:
    close(“test.txt”);

    3)输出到管道

    比如:

    awk -F "||" '{print "/" |"df" }' worker.txt
    输出:
    文件系统           1K-块     已用      可用 已用% 挂载点
    udev             1946180        4   1946176    1% /dev
    tmpfs             391988     1136    390852    1% /run
    /dev/dm-0      611014912 16737160 563216968    3% /
    none                   4        0         4    0% /sys/fs/cgroup
    none                5120        0      5120    0% /run/lock
    none             1959932      152   1959780    1% /run/shm
    none              102400       72    102328    1% /run/user
    /dev/sda1         240972   110988    117543   49% /boot 
    

    输入

    1)从file

    比如:
    awk '{print }' worker.txt
    输出:
    1||Jack||25||man||Chinese,FuJian
    2||Lip||30||man||American 
    

     
    2)从stdin

    比如:

    awk '{print }' //回显
    输入/输出:
    Hello,World
    Hello,World
    

    3)从pipe

    比如:

    cat worker.txt | awk '{print}'
    输出:
    1||Jack||25||man||Chinese,FuJian
    2||Lip||30||man||American 
    

    4)从getline

    名如其意,getline存在6中方式的调用:

    表达式 被设置的变量
    getline $0, NF, NR, FNR
    getline var var, NR, FNR
    getline <file $0, NF
    getline var <file var
    cmd | getline $0, NF
    cmd | getline var var

    注意:

    使用getline的返回值有3中情况1(存在记录),0(文件末尾),-1(打开失败或不存在)
    对于awk中的判断语句(if,while,for),0=false,非0=true
    所以如果你采用;
    awk 'END{while(getline < "no_exist_file") {print $0}}' empty.txt
    将进入无限的循环,所以正确的写法是:
    awk 'END{while(getline < "no_exist_file" > 0) {print $0}}' empty.txt

    下面来看下getline的具体用法:

    1)getline

    awk '{while(getline > 0) {print $0}}' worker.txt
    输出为:
    2||Lip||30||man||American
    

    2)getline var

    awk '{while(getline  var > 0) {print var}}' worker.txt
    输出为:
    2||Lip||30||man||American
    
    为什么1,2仅有一行输出呢?
    getline函数的功能在于抓取下一个记录.
    

    3)getline < file

    awk 'END{while(getline < "worker.txt" > 0) print $0,"NF=",NF}' empty.txt
    输出为:
    1||Jack||25||man||Chinese,FuJian NF= 1
    2||Lip||30||man||American NF= 1 
    

    4)getline var < file

    awk 'END{while(getline var< "worker.txt" > 0) print var}' empty.txt
    输出为:
    awk 'END{while(getline var< "worker.txt" > 0) print var}' empty.txt
    

    5)cmd | getline

    awk '{while("who" | getline > 0) print "NF(Current Line Splite Count):",NF,"data:",$0}' worker.txt
    输出为:
    NF(Current Line Splite Count): 5 data: lin      :0           2016-11-19 16:55 (:0)
    NF(Current Line Splite Count): 5 data: lin      pts/2        2016-11-19 19:57 (:0)
    NF(Current Line Splite Count): 5 data: lin      pts/13       2016-11-19 20:49 (:0)
    NF(Current Line Splite Count): 5 data: lin      pts/25       2016-11-19 21:16 (:0)
    

    6)cmd | get line var

    awk '{while("who" | getline line > 0) print line}' worker.txt
    输出为:
    lin      :0           2016-11-19 16:55 (:0)
    lin      pts/2        2016-11-19 19:57 (:0)
    lin      pts/13       2016-11-19 20:49 (:0)
    lin      pts/25       2016-11-19 21:16 (:0) 
    

    可以看出:

    直接采用awk的输入(文件/管道/标准输入)的情况使用getline,将根据实际情况设置$0(var),NR,FNR.

    凡事将getline重定向给var,那么NF将不会被设置(相反同义,凡是$0被设置后,NF就会被设置)

    与其他程序的交互

    1)使用pipe

    awk 'END{while("who" | getline line > 0) print line}' empty.txt
    输出为:
    lin      :0           2016-11-20 08:57 (:0)
    lin      pts/0        2016-11-20 09:02 (:0)
    

    2)使用system

    awk 'END{while(system("ls -lh") | getline line > 0) print line}' empty.txt
    输出为:
    总用量 20K
    -rw-rw-r-- 1 lin lin 256 11月  6 17:05 countries
    -rw-rw-r-- 1 lin lin   0 11月 19 23:09 empty.txt
    -rw-rw-r-- 1 lin lin  35 11月  6 16:53 ip.txt
    -rw-rw-r-- 1 lin lin  13 10月 28 22:51 print.sh
    -rw-rw-r-- 1 lin lin  29 11月 15 22:40 test.txt
    -rw-rw-r-- 1 lin lin  59 11月  9 22:24 worker.txt 
    

    总结

    本节主要讲述了awk 动作,动作主要的作用是用于对被模式匹配后的数据进行操作。

    参考

    祝:玩得愉快!
  • 相关阅读:
    hadoop 学习(一)ubuntu14.04 hadoop 安装
    Java开发笔记(三十四)字符串的赋值及类型转换
    Java开发笔记(三十三)字符包装类型
    Java开发笔记(三十二)字符型与整型相互转化
    Java开发笔记(三十)大小数BigDecimal
    Java开发笔记(二十九)大整数BigInteger
    Java开发笔记(二十八)布尔包装类型
    Java开发笔记(二十七)数值包装类型
    Java开发笔记(二十六)方法的输出参数
    Java开发笔记(二十五)方法的输入参数
  • 原文地址:https://www.cnblogs.com/hejianglin/p/6082755.html
Copyright © 2020-2023  润新知