zoukankan      html  css  js  c++  java
  • awk命令简介

    在shell命令或编程中,可以用AWK强大的的文本处理能力。如果要格式化报文或从一个 大的文本文件中抽取数据包,那么awk可完成这些任务。awk是一种解释的编程语言。awk也是shell过滤工具中最难掌握的。awk是一种自解释的编 程语言。结合awk和sed和grep,将会使awk编程更加容易。
    awk语言最基本的功能是在文件或字符串中基于指定的规则浏览和抽取信息。
    有三种方式可调用awk.
    <1>.命令行方式。
    <2>.将所有的awk命令插入一个文件,并利用chmod使awk文件成为执行。
    <3>.将所有的awk命令插入一个单独文件,然后调用。
    以下简单介绍awk的各种方式,详细请查看相关另外文档
    在awk中有四种概念。
    1.抽取域
    2.匹配正则表达式
    3.比较域
    4.向awk传递参数
    以下简单介绍:
    1).保存awk输出: #awk '{print $0}'  myfile>newfile
    2).使用tee,在输出到文件的同时输出到屏幕(利用管道'|')
         #awk '{print $0}' myfile |tee newfile
    3).打印报告头,#awk 'BEGIN {print "hello,this is Title\n---------"}{print $0}' newfile
    4).打印信息尾.#awk 'BEGIN{print $0} END {"end of file."}' myfile
    5).匹配,如下若在myfile第二列中带有BROWN,则打印信息
         #awk '{if ($2~/BROWN/) print $0}' myfile
    6).精确匹配,同上,只是将~改为==
    7).不匹配,有时要浏览信息并抽取不匹配操作的记录,与~相反的符号是!,如下
    #awk '$0 !~/BROWN/' myfile
    8).比较
     如小于: #awk 'if ($1<$2) print $1' myfile
    9).设置大小写 #awk '[Gg]reen/' myfile
    10).任意字符,表达式/^...a/意为前三个字符是任意字符
      #awk '$1~/^...a/' myfile
    11).或关系匹配,#awk '$0~/(YELLOW || RED)/' myfile
    12).与:&& ,或:||
    13).awk内置变量
     <1>. 要快速查看记录个数,应使用NR,如:#awk 'END {print NR}' myfile <2>.以下使用NF变量显示每一条读记录中有多少个域,并在END部份  打印输入文件名。#awk '{print NR,NF,$0} END {print FILENAME}' myfile
    <3>. 判断并输出 . #awk '{if(NR>0 && $4~/BROWN/) print $0' myfile
    14).可以设置输入域到域变量名。
    15).域值比较操作。
       @1.在BEGIN中给变量名赋值。通常在BEGIN部分赋值是很有益的,可以在awk表达式进行改动时减少很大麻烦.
       @2.在关系操作中使用实际数值,使用关系操作时必须用括号括起来.
     #awk '{if($6<27) print $0}' myfile
     #awk 'BEGIN {BASELINE="27"}{if ($6<BASELINE) print $6}' myfile
      17).修改数据域取值
     当在awk中修改任何域时,重要的一点是实际的文件可修改,改动的是cache中的awk复本,awk会在变量NR或NF中反映出修改的痕迹。
    #awk '{if($1=="M.TANS")$6=$6-1;print $6}' myfile
    18).修改文本域
     #awk '{if($1=="J.Troll")($1="J.L.Troll");print $1}' myfile
    19).只显示修改记录
    #awk '{if($1=="J.Troll"){$1="J.L.Troll";print $1}}' myfile
    20).创建新的输出域
    在awk中处理数据时,基于各域进行计算的创建新域是个好的习惯。如下示例:
     #awk 'BEGIN{print "Name    Score\t"}if($6<$7){$8=$7-$6;print $8}' myfile
    21).增加列值
     #awk 'tot+=$6;END{print "Club Total point." tot}' myfile
    22).使用模式打印文件名及其长度,放入变量tot中
    #ls -l | awk'/^[^d]{print $9 "\t" $5}{tot+=$5} END {print "Total KB:tot"}'
    23).awk内置的字符串函数
    24).awk脚本文件
    如以上的所述的诸多情况,这里只不过命令放在一个文件中,且该文件必须是!/bin/awk -f ,因为这样才会使这个文件可以自解释。否则将不能作用。为了容易分别,最好将文件带一个扩展名.awk,完成对文件的编写后,再利用chmod  u+x使文件可以执行。
       以上只是我在实验中的一些情况,awk命令功能很强大,大家可以参考其它的一些手册去获得更清楚的说明。

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    1.调用awk:
    第一种方式:命令行方式
    awk [-F field-separator] 'commands' input-file(s)
    [-F域分隔符]是可选的,因为awk使用空格作为缺省的域分隔符,因此如果要浏览域间有空格的文本,不必指定这个选项,如果要浏览诸如passwd文件,此文件各域以冒号作为分隔符,则必须指明-F选项,如:
    awk -F: 'commands' input-file
    第二种方式是将所有awk命令插入一个文件,并使awk程序可执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。
    第三种方式是将所有的awk命令插入一个单独文件,然后调用:
    awk -f awk-scrīpt-file input-files(s)
    -f选项指明在文件awk_scrīpt_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名。

    2.awk脚本
    2.1 模式和动作
    任何awk语句都由模式和动作组成。在一个awk脚本中可能有许多语句。模式部分决定动作语句何时触发及触发事件。处理即对数据进行的操作。如果省略模式部分,动作将时刻保持执行状态。
    模 式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段 BEGIN和END。使用BEGIN语句设置计数和打印头。BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文本开始执行。END语 句用来在awk完成文本浏览动作后打印输出文本总数和结尾状态标志。
    2.2 域和记录
    使用$1,$3表示参照第1和第3域,注意这里用逗号做域分隔。如果希望打印一个有5个域的记录的所有域,可使用$0,意即所有域。
    为打印一个域或所有域,使用print命令。这是一个awk动作
    (1) 抽取域
    (2) 保存awk输出
    $ awk '{print $0}' grade.txt > wow
    使用这种方法,显示屏上不会显示输出结果。直接输出到文件。
    使用tee命令,在输出文件的同时,输出到屏幕
    $ awk '{print $0}' grade.txt | tee delete_me_and_die
    (3) 使和标准输入
    使用awk脚本输入文件格式:
    ● $ belts.awk grade_student.txt
    ● $ belts.awk < grade2.txt
    ● $ grade2.txt | belts.awk
    (4) 打印所有记录
    $ awk '{print $0}' grade.txt
    (5) 打印单独记录
    $ awk '{print $1,$4}' grade.txt
    (6) 打印报告头
    域间使用\t进行划分。下划线使用\n强迫启动新行
    $ awk 'BEGIN {print "Name Belt\n----------------------------------"} {print $1"\t"$4}' grade.txt
    (7) 打印信息尾
    使用END语句
    $ awk 'BEGIN {print "Name\n---------"} {print $1} END {"end-of-report"}' grade.txt
    2.5 条件操作符
    (1) 匹配:
    $ awk '{if ($4~/Brown/) print $0}' grade.txt
    如果在文本中查询字符串"Brown",使用/Brown/
    $ awk '$0 ~ /Brown/' grade.txt
    (2) 精确匹配
    $ awk '$3 == "48" {print $0}' grade.txt
    $ awk '{if ($3=="48") print $0}' grade.txt
    (3) 不匹配
    $ awk '$0 !~ /Brown/' grade.txt
    $ awk '{if($4 !~ /Brown/) print $0' grade.txt
    精确不匹配
    $ awk '$4 != "Brwon-2" {print $0}' grade.txt
    (4) 小于
    $ awk '{if ($6 < $7) print $0 "$1 Try better at the next comp"}' grade.txt
    (5) 小于等于
    $ awk '{if ($6 <= $7) print $1}' grade.txt
    (6) 大于
    $ awk '{if ($6 > $7) print $1}' grade.txt
    (7) 设置大小写
    $ awk '/[Gg]reen/' grade.txt
    (8) 任意字符
    抽取名字,其记录第一域的第四个字符是a,使用句点.。表达式/^...a/意为行首前三个字符任意,第四个是a,尖角符号代表行首。
    $ awk '$1 ~/^...a/' grade.txt
    (9) 或关系匹配
    为抽取级别为yellow或brown的记录,使用竖线符|。意为匹配|两边模式之一。注意,使用竖线符时,语句必须用圆括号括起来。
    $ awk '$0~/(Yellow|Brown)/' grade.txt
    (10) 行首
    $ awk '/^48/' input-file
    (11) AND
    && 意味着两边匹配均为真
    $ awk '{if ($1 == "P.Bunny" && $4 == "Yellow") print $0}' grade.txt
    (12) OR
    $ awk '{if ($4 == "Yellow" || $4 ~ /Brown/) print $0}' grade.txt
    2.6 awk内置变量
      最常用的一些变量
    --------------------------------------------------------
     ARGC   命令行参数个数
     ARGV   命令行参数排列
     ENVIRON  支持队列中系统环境变量的使用
     FILENAME  awk浏览的文件名
     FNR   浏览文件的记录数
     FS   设置输入域分隔符,等价于命令行-F选项
     NF   浏览记录的域个数
     NR   已读的记录数
     OFS   输出域分隔符
     ORS   输出记录分隔符
     RS   控制记录分隔符
    --------------------------------------------------------
    2.7 NF、NR和FILENAME
    NR代表记录处数
    $ awk 'END {print NR}' grade.txt
    $ 5
    打印所有学生的记录,并带有其记录号,并在END部分打印输入文件名
    NF显示一条记录中有几个域
    $ awk '{print NF,NR,$0}END{print FILENAME}' grade.txt
    在从文件中抽取信息时,先检查文件中是否有记录。使用AND实现
    $ awk '{if (NR > 0 && $4~/Brown/) print $0}' grade.txt
    NF的强大功能是将变量$PWD的返回值传入awk并显示其目录。这里需要指定域分隔符
    $ pwd
    /usr/local/etc
    $ echo $PWD | awk -F/ '{print $NF}'
    另一个例子是显示文件名:
    $ echo "/usr/local/etc/rc.sybase" | awk -F/ '{print $NF}'
    rc.sybase
    2.8 awk操作符
    awk使用操作符,基本表达式可以划分为数字型、字符串型、变量型、域及数组元素,
    -----------------------------------------------------
     = += *= /= %= ^= 赋值操作符
     ?    条件表达操作符
     || && !   并、与、非
     ~ !~    匹配操作符,包括匹配与不匹配
     < <= == != >>  关系操作符
     + - * / % ^   算术操作符
     ++ --    前缀和后缀
    -----------------------------------------------------
    (1)设置输入域到域变量名
    一般的变量名设置方式为name = $n,这里name为调用的域变量名,n为实际域号。
    例如,设置学生域名为name,级别域名为belt,操作为name = $1; belts = $4。注意分号,它分隔awk命令。
    $ awk '{name = $1; belts = $4; if(belts ~/Yellow/) print name " is belt " belts}' grade.txt
    $ P.Bunny is belt Yellow
    (2) 域值比较操作
    有两种方式测试一数值域是否小于另一数值域
    1)在BEGIN中给变量名赋值。
    2)在关系操作中使用实际数值。
    查询所有比赛中得分在27点的学生
    $ awk '{if ($6 < 27) print $0}' grade.txt
    J.Lulu          06/99   48317   green   9       24      26
    J.Troll         07/99   4842    Brown-3 12      26      26
    使用BEGIN
    $ awk 'BEGIN {BASELINE="27"} {if ($6 < BASELINE) print $0}' grade.txt
    (3) 修改数值域取值
    当在awk中修改任何域时,修改的只是缓存里的awk复本。awk会在变量NR和NF变量中反映出修改痕迹。
    $1=$1+5,会将域1数值加5,但要确保赋值域其子集为数值型。
    修改M.Tansley的目前级别分域,
    awk '{if ($1 == "M.Tansley") $6=$6-1; print $1, $6, $7}' grade.txt
    (4) 修改文本域
    修改文本域即对其重新赋值。需要做的就是赋给一个新的字符串。
    $ awk '{if ($1 == "J.Troll") ($1 = "J.L.Troll"); print $1}' grade.txt
    (5) 只显示修改记录
    在模式后面使用花括号将只打印修改部分。取得模式,再根据模式结果实施操作。
    $ awk '{if ($1 == "J.Troll") {$1 = "J.L.Troll"; print $1}}' grade.txt
    (6) 创建新的输出域
    如创建一个基于其他域的加法新域{$4 = $2 + $3},假定记录包含3上域,则域4为新建域。
    在文件grade.txt中创建新域8保存域目前级别分与域域最高级别分的减法值。表达式为'{$8 = $7 - $6}',语法首先测试域目前级别分小于域最高组别分。
    $ awk 'BEGIN {print "Name\t Difference"} {if ($6 < $7) {$8 = $7 - $6; print$1, $8}}' grade.txt
    可以创建新域,赋给更有意义的变量名
    $ awk 'BEGIN {print "Name\t Difference"} {if ($6 < $7) {diff = $7 - $6; print$1, diff}}' grade.txt
    (7) 增加列值
    为增加列数或进行运行结果统计,使用符号 +=。增加的结果赋给符号左边变量值,增加到变量的域在符号右边。例如将$1加入变量total,表达式为total+=$1。
    将所有学生的'目前级别分'加在一起,方法是tot+=$6,tot即为awk浏览的整个文件的域6结果总和。
    $ awk '{(tot+=$6)}; END {print "Club student total points : " tot}' grade.txt
    Club student total points : 155
    (8) 文件长度相加
    在目录中查看文件时,快速查看所有文件的长度及其总和,但要排除子目录。使用ls -l,然后管道输出到awk
    $ ls -l | awk '/^[^d]/ {print $9"\t"$5} {tot+=$5} END {print "total KB : " tot}'
    data.f    193
    grade.txt       179
    grepstring      7
    local.cshrc     136
    local.login     157
    local.profile   174
    results.txt     2129
    wow       179
    total KB : 4690
    (9) 内置的字符串函数
       awk内置字符串函数
    -----------------------------------------------------------
     gsub(r,s)   在整个$0中用s替代r
     gsub(r,s,t)  在整个t中用s替代r
     index(s,t)   返回s中字符串t的第一个位置
     length(s)   返回s长度
     match(s,r)   测试s是否包含匹配r的字符串
     split(s,a,fs)  在fs上将s分成序列a
     sprint(fmt,exp)  返回经fmt格式化后的exp
     sub(r,s)   用$0中最左边最长的子串代替s
     substr(s,p)  返回字符串s中从p开始的后缀部分
     substr(s,p,n)  返回字符串s中从p开始长度为n的后缀部分
    -----------------------------------------------------------
    ■gsub:
    ■index:
    $ awk 'BEGIN {print index("Bunny", "ny")}' grade.txt
    4
    ■length:
    $ awk '$1 == "J.Troll" {print length($1)" "$1}' grade.txt
    7 J.Troll
    $ awk 'BEGIN{print length("A FEW GOOD MEN")}'
    14
    ■match:如果不存在,返回0
    ■split
    返回字符串数组元素个数。
    $ awk 'BEGIN {print split("123#456#678", myarray, "#")}'
    3
    ■sub
    使用sub发现并替换模式的第一次出现位置。字符串STR包含'poped popo pill',执行下列sub命令
    sub(/op/, "op", STR)。结果 'pOPed pope pill'
    $ awk '$1 == "L.Tansley" {print substr($1, 1, 5)}' grade.txt
    L.Tan
    ■substr:
    它按照起始位置及长度返回字符串的一部分。
    $ awk '$1 == "L.Tansley" {print substr($1, 1, 5)}' grade.txt
    L.Tan
    substr的另一种形式是返回字符串后缀或指定位置后面的字符
    $ awk '{print substr($1, 3)}' grade.txt
    在BEGIN部分定义字符串,在END部分返回从第t个字符开始抽取的子串。
    $ awk 'BEGIN {STR="A FEW GOOD MEN"} END {print substr(STR, 7)}' grade.txt
    GOOD MEN
    ■从shell中向awk传入字符串:
    通过管道把字符串传入awk
    $ echo "Stand-by" | awk '{print length($0)}'
    8
    设置文件名为一变量,管道输出到awk,返回不带扩展名的文件名
    $ STR="mydoc.txt"
    $ echo $STR | awk '{print substr($STR,1,5)}'
    mydoc
    (10)字符串屏蔽序列
    使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。
       awk中使用的屏蔽序列
    ------------------------------------------------------------
     \b 退格键   \t  tab键
     \f 走纸换页  \ddd  八进制值
     \n 新行    \c  任意其他特殊字符,例如\\为返斜线符号
     \r 回车键  
    ------------------------------------------------------------
    打印May Day,中间夹tab键,后跟两个新行,再打印May Day,这次使用八进制数
    $ awk 'BEGIN{print "May\tDay\n\nMay\t\104\141\171"}'
    (11) awk输出函数printf
       awk printf修饰符
    ----------------------------------------------------------------
      -   左对齐
      Width   域的步长,用0表示0步长
      .prec   最大字符串长度,或小数点右边的位数
    ----------------------------------------------------------------
       awk printf格式
    -------------------------------------------------------------
      %c   ASCII字符
      %d   整数
      %e   浮点数,科学记数法
      %f   浮点数,例如(123.44)
      %g   awk决定使用哪种浮点数转换e或者f
      %o   八进制数
      %s   字符串
      %x   十六进制数
    --------------------------------------------------------------
    ■ 字符转换
    观察ASCII码中65的等价值。管道输出65到awk。
    $ echo "65" | awk '{printf "%c\n", $0}'
    A
    当然也可以按同样方式使用awk得到同样结果
    $ awk 'BEGIN {printf "%c\n", 65}'
    A
    所有的字符转换都一样,下面的例子表示进行浮点数转换后'999'的输出结果。整数传入后被加了小数点。
    $ awk 'BEGIN {printf "%f\n", 999}'
    ■ 格式化输出
    打印所有的学生名字和序列号,要求名字左对齐,15个字符长度,后跟序列号。注意\n换行符放在最后一个指示符后面。输出将自动分成两列。
    $ awk '{printf "%-15s %s\n", $1, $3}' grade.txt
    M.Tansley       48311
    J.Lulu          48317
    P.Bunny         48
    J.Troll         4842
    L.Tansley       4712
    加入文本注释帮助理解报文含义。可在正文前嵌入头信息。
    $ awk 'BEGIN {print "Name \t\tS.Number"} {printf "%-15s %s\n", $1, $3}' grade.txt
    Name            S.Number
    M.Tansley       48311
    J.Lulu          48317
    P.Bunny         48
    J.Troll         4842
    L.Tansley       4712
    ■ 向一行awk命令传值
    在查看awk脚本前,先来查看怎样在awk命令行中传递变量。
    awk执行前将值传入awk变量,需要将变量放在命令行中,格式如下:
    awk 命令变量 = 输入文件值
    在命令行中设置变量AGE等于10,然后传入awk中,查询年龄在10岁以下的所有学生
    $ awk '{if ($5 < AGE) print $0}' AGE=10 grade.txt
    要快速查看文件系统空间容量,观察其是否达到一定水平。
    $ df -k | awk '($4 ~/^[0-9]/) {if ($4 < TRIGGER) print $6"\t"$4}' TRIGGER=56000
    使用who命令,who命令第一列包含注册用户名。
    # who | awk '{print $1 " is logged on"}'
    root is logged on
    root is logged on
    sun is logged on
    awk传入环境变量。使用环境变量LOGNAME支持当前用户名。
    # who | awk '{if ($1 == user) print $1 " you are connected to" $2}' user=$LOGNAME
    root you are connected toconsole
    root you are connected topts/4
  • 相关阅读:
    Vue双向绑定的实现原理系列(一):Object.defineproperty
    TCP协议中的三次握手和四次挥手
    一切事物皆对象_进阶篇
    一切事物皆对象_基础篇
    自成一派的正则表达式
    超好用的模块
    软件目录开发规范
    迭代器与生成器
    不怎么好吃的语法糖
    你可造什么是函数
  • 原文地址:https://www.cnblogs.com/buffer/p/1608950.html
Copyright © 2011-2022 走看看