zoukankan      html  css  js  c++  java
  • 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 动作,动作主要的作用是用于对被模式匹配后的数据进行操作。

    参考

    祝:玩得愉快!
  • 相关阅读:
    图像检索(image retrieval)- 11
    图像检索(image retrieval)- 10相关
    Mock.js简易教程,脱离后端独立开发,实现增删改查功能
    Azure Monitor (3) 对虚拟机磁盘设置自定义监控
    Azure Monitor (1) 概述
    Azure SQL Managed Instance (2) 备份SQL MI
    Azure Virtual Network (17) Private Link演示
    Azure Virtual Network (16) Private Link
    Azure Virtual Network (15) Service Endpoint演示
    Azure Virtual Network (14) Service Endpoint服务终结点
  • 原文地址:https://www.cnblogs.com/hejianglin/p/6082755.html
Copyright © 2011-2022 走看看