您的位置:首页 > 运维架构 > Shell

awk】1-awk基础篇(又名UNIX.Shell.awk)

2011-07-17 17:40 423 查看
导读:
1,awk基本语法
2,比较操作符
3,复合表达式
4,next命令
5,变量及变量赋值
6,awk中的赋值操作符
7,BEGIN和END
8,内置变量 
9,awk使用shell变量
10,awk中的三种流控制语句
10.1 if语句
10.2 while语句:
10.3 for语句:
11,实验:
12,shell里的特殊变量
正文:

1,awk基本语法

awk ‘script’  filesscript 由下面的结构组成 /pattern/{actions}例子:打印fruit_prices.txt文件的内容[root@master bkeep]# awk '{print;}' fruit_prices.txt fruit           price/lbs               quantitybanana          $0.89                   100peach           $0.79                   65kiwi            $1.50                   22pineapple       $1.29                   35apple           $0.99                   78TIPS:留意printf的用法 如果加“-”说明是左对齐![root@master bkeep]# awk '{printf "%-15s %s\n", $1, $3;}' fruit_prices.txtfruit           quantitybanana          100peach           65kiwi            22pineapple       35apple           78留意printf的用法 如果不加“-”说明是右对齐![root@master bkeep]# awk '{printf "%15s %s\n", $1, $3;}' fruit_prices.txt          fruit quantity         banana 100          peach 65           kiwi 22      pineapple 35          apple 78例子:给价格高于1美元的水果加个星号[root@master bkeep]# cat fruit_prices.txt fruit           price/lbs               quantitybanana          $0.89                   100peach           $0.79                   65kiwi            $1.50                   22pineapple       $1.29                   35apple           $0.99                   78[root@master bkeep]# cat price.sh #!/bin/bashawk '   / *\$[1-9][0-9]*\.[0-9][0-9] */ {print $1,$2,$3,"*";} //星号前面一定要留空格,否则匹配不到   / *\$0\.[0-9][0-9] */ {print;}       //以后养成习惯,/ key /斜杠和key之间始终留空格' fruit_prices.txt执行结果:[root@master bkeep]# ./price.sh banana          $0.89                   100peach           $0.79                   65kiwi $1.50 22 *pineapple $1.29 35 *apple           $0.99                   78上面的格式很不好看,我们改改它吧!TIPS:$0:awk使用变量0原原本本地存储它所读入的整个输入行。这样可以保持和原来文本格式相同的输出[root@master bkeep]# cat price.sh         #!/bin/bashawk '   / *\$[1-9][0-9]*\.[0-9][0-9] */ {print $0,"*";}   / *\$0\.[0-9][0-9] */ {print;}' fruit_prices.txt[root@master bkeep]# ./price.sh banana          $0.89                   100peach           $0.79                   65kiwi            $1.50                   22 *pineapple       $1.29                   35 *apple           $0.99                   78

2,比较操作符

语法:expression {actions;}expression 可以使用以下操作符构成<                                 小于>                                 大于<=                               小于等于>=                               大于等于==                               等于!=                               不等于value ~ /pattern/          若value匹配pattern则为真value !~ /pattern/         若value不匹配pattern则为真说明:$2 ~ /^\$[1-9][0-9]*  将匹配第二列以$开头,然后大于1的二位数。(注意,这里是1而不是10)例子:给数量大于50的水果加星号[root@master bkeep]# cat larger.sh #!/bin/bashawk '    $3>50 {printf "%s\t%s\n", $0,"*"}    $3<=50 {printf "%s\n",$0}' fruit_prices.txt[root@master bkeep]# ./larger.sh fruit           price/lbs               quantity        *banana          $0.89                   100     *peach           $0.79                   65      *kiwi            $1.50                   22pineapple       $1.29                   35apple           $0.99                   78      *

3,复合表达式

语法:(compound expression)(expr1)&& (expr2)  ------- 与(expr1)|| (expr2)  ------- 或说明一下:符合表达式必须用括号括起来当使用&&时,expr1和expr2必须同时为零(零代表真!呵呵~),复合表达式才为真;当使用 || 时,expr1和expr2 只要有一个为真,复合表达式则为真!例子:显示价格高于1美元且数量少于50的水果记录,给打个标记![root@master bkeep]# cat larger.sh #!/bin/bashawk ' ($2 ~ /^\$[1-9][0-9]*\.[0-9][0-9]$/) && ($3<50) {  //这是一个模式匹配(请参阅比较操作符 printf "%s\t%s\t%s\n", $0,"*","reorder";}' fruit_prices.txt[root@master bkeep]# ./larger.sh kiwi            $1.50                   22      *       reorderpineapple $1.29 35 * reorder

4,next命令

例子:给库存少于50的水果价格标签![root@master bkeep]# cat next.sh #!/bin/bashawk '   $3 <= 50 { printf "%s\t%s\n",$0,"REORDER" ; }   $3 > 50 {print $0; }' fruit_prices.txt当输入行为:kiwi    $1.50      22脚本执行以下过程:1)检查是否第三列的值22小于50,由于值小于50,执行脚本的第二步2)打印该行,并在行尾添加REORDER标志3)检查是否第三列的值22大于50,由于值不大于50,脚本读下一行呵呵,傻子都看得出这种情况下执行第三步是多余的。那么如何跳过呢?可以使用next命令。next命令:告诉awk跳过剩下的所有模式和表达式,并读取输入的下一行,同时从第一个模式或表达式开始处理该行!修改后的脚本,加入了next命令![root@master bkeep]# cat next.sh #!/bin/bashawk '   $3 <= 50 { printf "%s\t%s\n",$0,"REORDER" ;next; }   $3 > 50 {print $0; }' fruit_prices.txt[root@master bkeep]# ./next.sh fruit           price/lbs               quantitybanana          $0.89                   100peach           $0.79                   65kiwi            $1.50                   22      REORDERpineapple       $1.29                   35      REORDERapple           $0.99                   78现在脚本执行如下;1)检查是否第三列的值22小于50,由于值小于50,所以执行脚本第二步2)打印输出行并在该行后打印REORDER标志(有了next后就不再执行$3 > 50 {print $0; })3)读取下一输入行并从第一种模式开始

5,变量及变量赋值

下面给变量赋值fruit=100   //把数字赋给fruit变量fruit=”peach”  //把字符串赋给fruit变量fruit=$1      //把第一列赋给fruit变量awk中的数字操作符:+            加-             减*            乘/             除%           求余^            求幂应用例子:统计文件中的空行数[root@master bkeep]# cat for.sh #!/bin/bashfor i in $@;    //这里我们不知道有多少个文件需要统计,所以用$@来接收参数!do   if [ -f $i ]; then      echo $i      awk ' /^$/ { x=x+1;} END{print x;}' $i    else      echo "ERROR:$i not a file." >&2    fidone[root@master bkeep]# ./for.sh aa bbaa                  //文件名为aa7                   //空行数7bb                  //文件名为bb4                   //空行数为4

6,awk中的赋值操作符

+=                 x+=1 就是x=x+1-=                  x-=1 就是x=x-1*=                 x*=1 就是x=x*1/=                  x/=1 就是x=x/1%=                x%=2 就是x=x%2^=                 x^=2 就是x=x^2

7,BEGIN和END

awk的语法:/pattern/ {action}    pattern:模式这里pattern有两个特殊模式BEGIN和END下面是BEGIN  END的语法:awk ‘BEGIN { actions }/ pattern / { actions }/ pattern / { actions }END { actions }‘  filesBEGIN和END都是可选的·当指定BEGIN模式时,awk在读取任何输入前执行动作 actions·当指定END模式时,awk在其退出前执行动作actions这里要特别注意:比如awk读入aa.txt。那么BEGIN只在读入aa时执行一次,然后按行处理的时候不再执行BEGIN指定的action!(也可以这么理解:BEGIN只对文件生效,而不是按行生效!!);理解了BEGIN,END还会糊涂吗?呵呵!

8,内置变量

gawk语言中有几个十分有用的内置变量,现在列于下面:
NR 已经读取过的记录数。
FNR 从当前文件中读出的记录数。
FILENAME 输入文件的名字。
FS 字段分隔符(缺省为空格)。
RS 记录分隔符(缺省为换行)。
OFMT 数字的输出格式(缺省为% g)。
OFS 输出字段分隔符。
ORS 输出记录分隔符。
NF 当前记录中的字段数。
如果你只处理一个文件,则NR 和FNR 的值是一样的。但如果是多个文件, NR是对所有的文件来说的,而FNR 则只是针对当前文件而言。例子:统计空行的脚本:[root@master bkeep]# cat for.sh #!/bin/bashfor i in $@;do   if [ -f $i ]; then#      echo $i      awk 'BEGIN { printf "%s\t",FILENAME;}   //输出文件名         /^$/ { x+=1;}                    //统计空行       END{avg=100*(x/NR); printf "%s\t%3.1f\n",x,avg;}' $i   //最后算百分比及打印结果    else      echo "ERROR:$i not a file." >&2    fidone[root@master bkeep]# ./for.sh aa bb  //显示出来的结果很漂亮。可惜了,文件名没出来!        7       87.5                      //怀疑FILENAME内置变量被修改了???        4       57.1

9,awk使用shell变量

经过前面的学习,我们知道shell变量的引用由$xxx 实现,而awk中的变量直接使用xxx来引用。所以我们就要思考如何让awk使用shell变量语法:awk  ‘script’  awkvar1=value  awkvar2=value ......  files说明: awk: 命令; ‘script’:awk将要执行的脚本; awkvarN:awk的变量;value:shell中的变量值; files:将要处理的文件名【重点实验—记忆】例子:根据用户提供的水果数量,将低于这个值的水果打印出来![root@master bkeep]# cat awk_var.sh #!/bin/bashNUM_FRUIT="$1"       //将用户输入传递给shell变量NUM_FRUITif [ -z "$NUM_FRUIT" ]; then NUM_FRUIT=75;fi  //如果用户没有输入,则赋默认值75awk '    $3 <= num_fruit {print;}      //最终将用户输入传递给awk变量num_fruit'  num_fruit="$NUM_FRUIT"  fruit_prices.txt   //通过此方法将$NUM_FRUIT//赋值给num_fruit;即把shell变量赋给awk执行结果:[root@master bkeep]# ./awk_var.sh 40        //将数量低于40的水果打印出来kiwi            $1.50                   22pineapple       $1.29                   35[root@master bkeep]# ./awk_var.sh 30     //将数量低于30的水果打印出来kiwi            $1.50                   22

10,awk中的三种流控制语句

if语句while语句for语句

10.1 if语句

if (expression1) {action1} else if (expression2) {action2} else { action3}执行过程:1)计算expression1的值2)若expression1为真,执行action1并推出if语句3)若expression1为假,计算expression24)若expression2为真,执行action2并退出if语句5)若expression2为假,执行action3并退出if举例:若水果价格高于1美元,那么给它加星号;若水果数量少于50,则给它加REORDER[root@master bkeep]# cat reorder.sh #!/bin/bashawk '{   printf "%s\t",$0;   if ( $2 ~ /\$[1-9][0-9]*\.[0-9][0-9]/ ) {        printf " * ";        if ($3 <= 75) {        printf "REORDER\n";        } else {           printf "\n";        }   }else {        if ($3<=75) {        printf "REORDER\n";        }else {              printf "\n";        }   }}' fruit_prices.txt执行结果:[root@master bkeep]# ./reorder.sh fruit           price/lbs               quantitybanana          $0.89                   100peach           $0.79                   65      REORDERkiwi            $1.50                   22       * REORDERpineapple       $1.29                   35       * REORDERapple           $0.99                   78

10.2 while语句:

while (expression) { actions }若expression为真,则执行actions[root@master bkeep]# awk 'BEGIN { x=0;while(x<3) {x+=1;print x;}}'   //先给x+1再输出123[root@master bkeep]# awk 'BEGIN { x=0;while(x<3) {print x;x++}}'   //先输出再给x+1012Tips:do语句是while语句衍生出来的;区别在于do至少执行一次,while有可能不执行

10.3 for语句:

for (initialize_counter; test_counter;increment_counter) {     action}解释一下,呵呵for (初始化计数器变量;测试计数器是否到顶了;增加计数器的值)  {   要执行的动作!}【常用】例子:循环迭代处理记录中的域并输出他们[root@master bkeep]# cat for2.sh #!/bin/bashawk '{    for (x=1;x<=NF;x+=1) {      printf "%s    ",$x "zbb";    }    printf "\n";}' fruit_prices.txt[root@master bkeep]# ./for2.sh fruitzbb    price/lbszbb    quantityzbb    bananazbb    $0.89zbb    100zbb    peachzbb    $0.79zbb    65zbb    根据输出我们重点理解下awk中for循环的执行过程1)读取一行数据2)执行for循环,处理每一个字段,将其输出,退出for循环3)执行第二个action即输出一个换行符4)重复1~3,直到处理完所有行!

11,实验:

例子:倒序显示记录中的每个行方法一:用for实现#!/bin/bashawk '{a[NR]=$0};         //第一个action:把记录存储在一个数组里面END{for (x=NR;x>0;x-=1) {              //第二个action:for循环,x=NR总行数       printf "%s\n",a[x];          //如果x>0,则x=x-1,倒序输出a[x]数组中的内容!       }}' fruit_prices.txt   //要处理的文件名!方法2:用while实现#!/bin/bashawk '{line[NR] = $0 }   //把所有记录都存放到数组里面END {var=NR      //把总行数赋给变量varwhile (var > 0){   //当var大于0时,执行后面的actionprint line[var]var--                            //var=var-1}}' fruit_prices.txt    //文件名执行结果:[root@master bkeep]# ./re.shapple           $0.99                   78pineapple       $1.29                   35kiwi            $1.50                   22peach           $0.79                   65banana          $0.89                   100fruit           price/lbs               quantity

12,shell里的特殊变量

# sh /usr/local/bkeep/shell.sh 001 002I'm $0 is:/usr/local/bkeep/shell.sh         //正在被执行脚本的名字;`basename $0`I'm $1 is:001                 //$1接收到的参数I'm $2 is:002                 //$2接收到的参数I'm $# is:2                    //总共接收到的参数个数I'm $* is:001 002          //把接收到的参数全部打印出来I'm $@ is:001 002         //同上I'm $? is:0                    //上一个脚本的退出状态“0”代表正常;“1”非正常退出I'm $$ is:24137             //当前执行脚本的进程IDI'm $! is:                      //前一个后台进程的id例子:再进一步解释下$*和$@吧;仔细看下面的例子,我就不废话了![root@master bkeep]# cat shell.sh #!/bin/bashcc=$*echo "I'm \$1 is:$1"echo "I'm \$2 is:$2"echo "I'm \$* is:$*"echo "I'm \$4 is:$4"[root@master bkeep]# ./shell.sh 11 22 33 "44" 55I'm $1 is:11I'm $2 is:22I'm $* is:11 22 33 44 55I'm $4 is:44应用例子:统计文件中的空行数[root@master bkeep]# cat for.sh #!/bin/bashfor i in $@;    //这里我们不知道有多少个文件需要统计,所以用$@来接收参数!do   if [ -f $i ]; then      echo $i      awk ' /^$/ { x=x+1;} END{print x;}' $i    else      echo "ERROR:$i not a file." >&2    fidone[root@master bkeep]# ./for.sh aa bbaa                  //文件名为aa7                   //空行数7bb                  //文件名为bb4                   //空行数为4
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息