zoukankan      html  css  js  c++  java
  • linux工具-awk

    1. 基本知识

    1.1. 名称由来

    awk是其设计者名字首字母.

    1.2. 语法格式

    awk [options] 'pattern {action}' filename
    

    1.3. 执行流程

    对如下语句:

    awk 'BEGIN {action1} pattern {action2} END {action3}' filename
    

    执行流程如下:

    1. 执行BEGIN {action1}语种块中的语句.
    2. 从文件或STDIN逐行读取, 对每一行执行pattern {action2}, 直到全部读取完成.
    3. 执行END {action3}语种块中的语句.

    例子: 打印每一行, 并且在开头和结尾分别打印Start和END.print语句不带参数时就打印整行内容

    例子:对第2列进行累加, 在BEGIN中为i赋初值, 在END中打印i(累加结果).

    $ echo -e "a 1 a
    a 2 a
    a 3 a" |   
    > awk 'BEGIN {i=0} {i+=$2} END {print i}'  
    6  
    

    1.4. 术语解释

    术语 说明
    记录 awk把每一个以换行符结束的行称为一个记录, NR即记录的个数
    记录中每个单词称做"域", 默认以空格或Tab分隔, NF即域的个数.

    2. options

    选项 说明
    -v 参数传递
    -f 指定脚本文件
    -F 指定分隔符
    -V 查看awk版本号

    例子1:指定列分隔符

    文件内容

    $ cat demo.txt  
    root:x:0:0:root:/root:/bin/bash  
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin  
    bin:x:2:2:bin:/bin:/usr/sbin/nologin  
    sys:x:3:3:sys:/dev:/usr/sbin/nologin  
    sync:x:4:65534:sync:/bin:/bin/sync  
    

    通过-F指定列分隔符

    $ # -F和:之间没有空格  
    $ awk -F: '{printf "%-6s %-9s %s
    ", $1, $6, $7}' demo.txt  
    root   /root     /bin/bash  
    daemon /usr/sbin /usr/sbin/nologin  
    bin    /bin      /usr/sbin/nologin  
    sys    /dev      /usr/sbin/nologin  
    sync   /bin      /bin/sync  
    $   
    $ # -F和:之间有空格, 这时分隔符最好放到引号中, 否则使用#等分隔时会报错.  
    $ awk -F ':' '{printf "%-6s %-9s %s
    ", $1, $6, $7}' demo.txt  
    root   /root     /bin/bash  
    daemon /usr/sbin /usr/sbin/nologin  
    bin    /bin      /usr/sbin/nologin  
    sys    /dev      /usr/sbin/nologin  
    sync   /bin      /bin/sync  
    

    通过-v FS指定列分隔符

    $ awk -v FS=: '{printf "%-6s %-9s %s
    ", $1, $6, $7}' demo.txt  
    root   /root     /bin/bash  
    daemon /usr/sbin /usr/sbin/nologin  
    bin    /bin      /usr/sbin/nologin  
    sys    /dev      /usr/sbin/nologin  
    sync   /bin      /bin/sync  
    

    3. pattern {action}

    awk_script由pattern和Action组成,
    例如:

    awk 'BEGIN {action1} pattern {action2} END {action3}' filename
    

    模式:有4种模式

    1. /正则表达式/
    2. 关系表达式:使用运算符进行操作, 比如字符串、数字的比较测试.
    3. 模式匹配表达式:用运算符:~和~!, 分别表示匹配、不匹配.
    4. BEGIN/END语句块、pattern语句块.

    action:由一个或多个命令/函数/表达式组成, 它们之间用换行符或分号隔开.
    action主要有以下类型:

    1. 变量或数组赋值
    2. 输出命令
    3. 内置函数
    4. 控制流语句

    注意:

    1. BEGIN {action1}, 只在开始执行一次, 是可选的, 默认无BEGINaction.
    2. pattern {action2}, 对匹配pattern的行进行操作, pattern是可选的, 默认对每一行进行action2, {action2}也是可选的, 默认打印匹配pattern的行, 但是pattern和{action2}必须出现一个, 不能都省略.
    3. END {action3}, 只在结尾执行一次, 是可选的, 默认无END action.

    例子1:
    输入文件内容:

    $ cat a.txt  
    line first    1  
    line second   2  
    line third    3  
    line forth    4  
    line fifth    5  
    line sixth    6  
    line seventh  7  
    

    使用BEGIN、END等

    $ # 在BEGIN的action中, 先打印一行内容, 再给i赋初值  
    $ # 在遍历line的语句中, 打印第2、3列, 并对第3列累加  
    $ # 在END的action中, 打印第3列的累加结果  
    $ awk 'BEGIN {print "C2", "C3"; i=0} {print $2, $3; i+=$3} END {print "total=",i}' a.txt  
    C2 C3  
    first 1  
    second 2  
    third 3  
    forth 4  
    fifth 5  
    sixth 6  
    seventh 7  
    total= 28  
    

    注意:

    1. 在print语句中,
      字符串要写在双引号里,
      字符串之间用逗号分隔,
      变量可以直接赋初值,
      变量使用时不能带双引号
    2. 变量赋值和使用时不需要带$号($1/$2等不受此限制)
    3. 多个action语句之间使用分号分隔.

    4. 运算符

    运算符 说明
    赋值运算符 --------
    = 赋值语句
    逻辑运算符 --------
    || 逻辑或
    && 逻辑与
    正则运算符 --------
    ~ 正则匹配
    ~! 正则不匹配
    关系运算符 --------
    <, <= 小于, 小于等于
    >, >= 大于, 大于等于
    == 等于
    != 不等于
    算术运算符 --------
    +, - 加, 减
    *, /, % 乘, 除, 取余
    +, -, ! 一元加/减/非
    ^, ***
    ++, -- 自增, 自减
    其它运算符 --------
    $ 字段引用
    空格 字符串连接
    ?: 三元运算
    in 元素是否存在于数组

    例: 只处理奇数行并输出

    $ awk -F: 'NR%2==1 {printf "%s) %-6s %-9s %s
    ", NR, $1, $(NF-1), $NF}' demo.txt  
    1) root   /root     /bin/bash  
    3) bin    /bin      /usr/sbin/nologin  
    5) sync   /bin      /bin/sync  
    

    例: 只处理$1等于root或bin的行, 使用||

    $ awk -F: '$1=="root"||$1=="bin" {printf "%s) %-6s %-9s %s
    ", NR, $1, $(NF-1), $NF}' demo.txt  
    1) root   /root     /bin/bash  
    3) bin    /bin      /usr/sbin/nologin  
    

    5. 内置变量

    内置变量 说明
    命令行 --------
    ARGC 命令行参数个数
    ARGV 命令行参数数组
    文件名 --------
    FILENAME 当前文件名
    计数 --------
    FNR 各文件分别计数的行号
    NF 当前行的字段个数(当前行分成了几列)
    NR 行号
    分隔符 --------
    FS 输入字段分隔符, 默认为空白字符
    OFS 输出字段分隔符, 默认为空白字符
    RS 输入记录分隔符(输入换行符)
    ORS 输出记录分隔符(输出换行符)
    记录 --------
    $0 完整的输入记录
    $n 当前记录的第n个字段, 字段间由FS分隔

    例: 使用NF, NF表示字段数, 本例中NF=7, $NF即$7表示最后一个字段, $(NF-1)表示倒数第二字段

    $ awk -F: '{printf "%-6s %-9s %s
    ", $1, $(NF-1), $NF}' demo.txt  
    root   /root     /bin/bash  
    daemon /usr/sbin /usr/sbin/nologin  
    bin    /bin      /usr/sbin/nologin  
    sys    /dev      /usr/sbin/nologin  
    sync   /bin      /bin/sync  
    

    例: 使用NR, NR表示当前行的行号

    $ awk -v FS=: '{printf "%s) %-6s %-9s %s
    ", NR, $1, $(NF-1), $NF}' demo.txt  
    1) root   /root     /bin/bash  
    2) daemon /usr/sbin /usr/sbin/nologin  
    3) bin    /bin      /usr/sbin/nologin  
    4) sys    /dev      /usr/sbin/nologin  
    5) sync   /bin      /bin/sync  
    

    6. 变量

    awk中, 变量不需要定义就可以直接使用, 变量类型可以是数字或字符串.

    例:如果第一个域匹配test, 则把第二第三个域相加并打印.

    awk '$1 ~ /test/ {count=$2+$3; print count}' filename
    

    域变量可以修改:
    例: 如果第一个域等于"root", 则把它赋值为test并打印.

    awk '$1=="root" {$1="test"; print}' filename
    

    7. 条件语句

    if语句

    如果第三个域大于3, 则打印一个第二第三域和一个"match"字符, 各字符之间可以有空格, 也可以没有, 字符串要写到双引号中.

    awk '{if ($3>3) print $2 "	" $3 "	" "match"}' a.txt
    

    if-else if-else语句
    有多个分支, 各分支的语句要写在大括号中.

    awk '{if ($3<=2) {print "0~2"} else if ($3<=4) {print "3~4"} else {print "5~n"}}' a.txt
    

    8. 循环语句

    1. awk有三种循环:while、for、special for
    2. 可以使用break和continue.
    3. next语句从输入文件中读取一行, 然后从头开始执行awk脚本.
    4. exit语句用于结构awk程序, 但不会略过END块.

    例子:

    awk '{i=1; while(i<=NF){print i, $i; i++}; print "------"}' a.txt
    

    说明:

    1. NF是当前行(记录)的字段(域)数量, $i是第i个字段(从1开始).
    2. 注意:print语句中, i和$i是不同的东西, i是循环变量, $i是第i个字段.
    3. 本例以字段数为循环条件, 遍历每个字段并打印.

    例子:

    awk '{for (i=1;i<=NF;i++) {print i, $i}; print "------"}' a.txt
    

    说明:作用同上, 将while语句改为for语句实现.

    special for用来遍历关联数组.见关联数组.for(i in name) {print i, name[i]}

    9. 数组

    在awk中数据的下标可以是数字, 也可以是字母(称为关联数组, 类似于python中的字典).

    例子:

    awk '{name[i++]=$2} END {for (i=0;i<NR;i++) {print i, name[i]}}' a.txt
    

    说明:

    1. 将每行的第二字段存入数组, 在结尾遍历数组并打印.
    2. name是一个数组, 不用声明, 直接赋值.
    3. 给数组赋值时, 直接对下标赋值, 不需要管该下标是否存在.
    4. 数组下标变量i自动初始化为0, 然后每处理一个记录自动加1.
    5. NR是当前行的行号(从1开始), 在END块中NR自动变成总行数, 用来遍历数组.

    例子:

    awk '/s/ {name[NR]=$2} END {for(i in name) {print i, name[i]}}' a.txt
    

    说明:

    1. 如果某行匹配/s/, 则给数组赋值, 下标是行号, 值是$2, 在结尾遍历数组.
    2. name的下标虽然是数字, 但可以是不连续的.

    10. 内置函数

    https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din

    函数 作用
    toupper() 字符串转为大写
    tolower() 字符串转为小写
    length() 返回字符串长度
    substr() 返回子字符串
    sin() 正弦
    cos() 余弦
    sqrt() 平方根
    rand() 随机数

    例: 使用toupper()将第一字段转为大写

    $ awk -F: '{printf "%s) %-6s %-9s %s
    ", NR, toupper($1), $(NF-1), $NF}' demo.txt  
    1) ROOT   /root     /bin/bash  
    2) DAEMON /usr/sbin /usr/sbin/nologin  
    3) BIN    /bin      /usr/sbin/nologin  
    4) SYS    /dev      /usr/sbin/nologin  
    5) SYNC   /bin      /bin/sync  
    
  • 相关阅读:
    在Flex (Flash)中嵌入HTML 代码或页面—Flex IFrame
    让Android App启动更协调
    最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter
    weblogic 内存 及 内存溢出
    Mysql或者Hive数据行变成列
    使用sphinx生成美观的文档
    adb 功能大全
    Problem B: Excuses, Excuses!
    2014acm亚洲区域赛陕西赛总结
    Cookie的写入,和读取
  • 原文地址:https://www.cnblogs.com/gaiqingfeng/p/13645984.html
Copyright © 2011-2022 走看看