gawk   gawk学习笔记    IBM awk资料

语法:

gawk  'script'  files

script如下所示:

/pattern/  { actions  }


假定fruit.txt文件的内容如下:

Fruit            Frice/lbs            Quantity
Banana           $0.89                100
Peach            $0.79                65
Kiwi             $1.50                22
Pineapple        $1.29                35
Apple            $0.99                78

例7-1. 相对于数据文件fruit.txt的一组示例

输出所有内容

1). gawk '{ print ; }' fruit.txt

输出指定字段

2). gawk '{ print $1,$3 ; }' fruit.txt

以特定格式输出指定字段

3). gawk '{ printf "%-15s %s",$1,$3 ; }' fruit.txt

在模式中使用正则表达式

4). gawk '  /\$[1-9][0-9]*\.[0-9[0-9]*/ {print $1,$2,$3;} /\$0\.[0-9][0-9]*/{prints ; } ' fruit.txt

在模式中使用关系表达式

5). gawk '$3<=75 { printf "%s%t%s\n",$0,"REORDER" ; } $3>75 print $0; ' fruit.txt

在模式中使用匹配、正则表达式、关系表达式、逻辑表达式样

6). gawk '($2 ~ /^\$[1-9][0-9]*\.[0-9][0-9]$/) && ($3<75){ printf "%s%t%s%t%s",$0,"*","REORDER" ; }' fruit.txt

查看IP地址

7). ifconfig | gawk '/inet/{print $2}' | gawk -F: '{print $2}'


数据文件employees的内容如下:

Tom Jones        4424    5/12/66    543354
Mary Adams       5346    11/4/63    28765
Sally Chang      1645    7/22/54    650000
Billy Black      1683    9/23/44    336500

例7-2. 关于数据文件employees的一组例子

模式匹配

1). gawk '/Sally/{print $1,$2}' employees

gawk的数据来源于管道

2). df | gawk '$4>75000{print}'

3). rusers | gawk '/root$/{print $1}'

4). date | gawk '{print "Month:" $2 "\nYear:",$6}'

利用-F选项指定字段分隔符

5). gawk -F: '/Tom Jones/{print $1,$2}' employees

6). gawk -F'[ :\t]'  '{print $1,$2}' employees

使用"~"针对某个字段进行模式匹配

7). gawk '$1 ~ /[Bb]ill/{print $0}' employees

8). gawk '$1 !~ /ly$/{print $0}' employees

9). gawk '$2 ~ /E/{print $1,$2}' employees

在模式,或字段模式中使用正则表达式

10). gawk '/^[ns]/{print $1}' employees

11). gawk '$5 ~ /\.[7-9]+/{print $0}' employees

在操作中使用条件表达式

12). gawk '{m=($1>$2)?$1:$2 ;print m}' employees

如果第一和第二个域相加大于100,则打印这些行。

13). gawk '$1 + $2 < 100' test

如果第一个域大于5,并且第二个域小于10,则打印这些行。

14). gawk '$1 > 5 && $2 < 10' test

gawk函数

15). gawk 'NR==1 {gsub(/northwest/,"southeast",$1);print}' test

16). gawk '{print substr($3,1,3);print length($3)}' employees

17). gawk '{print index($1,"ao")}' employees

18). gawk 'BEGIN{split("10/14/2001",now,"/");print now[1],now[2],now[3]}' test

读输入(getline)

19). gawk 'BEGIN{while(getline < "/etc/passwd" >0) {lc++} print lc}' datafile


例7-3. 输出多个文件(由命令行参数指定)中空行数目

#!/bin/bash

for i in  $@

do

    if [ -f $i ];then

        echo $i

        gawk '/^ *$/ { x=x+1; print x; }' $i

    else

        echo "Error $i is not a file" >&2

    fi

done


例7-4. 输出多个文件(由命令行参数指定)中空行数目--只输出一次(在gawk中使用END)

#!/bin/bash

for i in  $@

do

    if [ -f $i ];then

        echo "$i\c"

        gawk '/^ *$/ { x=x+1; next; } END {printf "%s\n",x; }' $i

    else

        echo "Error $i is not a file" >&2

    fi

done


例7-5. 订购数量在75以下的货物,并在单价高于1元的货物后加上"*"(在gawk中使用if条件)

awk '{
      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.txt


例7-6. 将文件各行字段按相反的顺序输出(在gawk中使用while循环)

#!/bin/bash

gawk '{ x=NF;

while (x>0)

    {

        printf("%16s",$x);

        x-=1;

    }

    print " ";

 }' fruit.txt


例7-7. 将文件各行字段按相反的顺序输出(在gawk中使用for循环)

#!/bin/bash

gawk '{

for (x=1;x<=NF;x+=1)

    {

        printf  "%s", $x;

    }

    printf "\n";

 }' fruit.txt


例7-8: gawk脚本1

脚本文件gawkfile文件的内容如下:

/^Mary/{print "Hello Mary!"}
{print $1,$2,$3}

执行脚本文件中的操作,可采用:

# gawk -f gawkfile employeess


例7-9: 对记录进行多种操作

利用gawk脚本对/etc/passwd文件进行数据合法性检验(如果字段数不等于7,或字段1不包含任何字母和数字字符,或字段2是一个*,则输出相应的提示信息).

# cat /etc/passwd | gawk -F: '\

NF!=7 {printf("line %d,does not have 7 fields:%s\n",NR,$0)} \

$1 !~ /[A-Za-z0-9]/{printf("line %d:nonealphanumeric user id:%s\n",NR,$0)} \

$2 == "*" {printf("no password: %s\n",$0)}'


例7-10: 数组初步

1. 将文件employees中第二个字段的值保存在数组name中,并输出.

gawk '{name[x++]=$2};END{for(i=0;i<NR;i++) \

print i,name[i]}' employees

2.将文件employees中第三个字段的值保存在数组id中,并输出(使用字段下标的形式).

gawk '{id[NR]=$3};END{for(x=1;x<=NR;x++) \

print id[x] }' employees

3.将文件employees中第三个字段的值保存在数组id中,并输出(使用for in形式).

gawk '{id[NR]=$3};END{for(x in id) \

print id[x] }' employees

4. gawk 'BEGIN{ numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")};\

END{for(x in mymonths) \

print mymonths[x] }} '


例7-11: 自定义函数

#!/usr/bin/env awk -f
BEGIN {
FS="\t+"
months="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
}
function monthdigit(mymonth) {
return (index(months,mymonth)+3)/4
}

END{
print monthdigit("Mar")
}


例7-12: 脚本文件与自定义函数

针对练习中的数据文件,编写一个用户自定义函数,要求函数能返回指定月份的人均捐款数额,月份由命令行传入

#cat awkf

BEGIN {
total=0
n=0
}
function mon_avg(curmonth) {
curmonth=4+curmonth
total+=$curmonth
n++
return total/n;
}

{
x=mon_avg(argv[1])
}

END{
print "The end is",x
}

#gawk -f awkfile datafile


例7-13: 批量添加系统用户

这个脚本还有很多地方需要改进,比如算法,比如数据的处理。
希望大家不吝提出修改意见。

[code:1:22892b664a]
#!/bin/sh
# Name: useraddmuti
# Descripton: To add users to your system. Users can be list in a file.
# To exec this command your ID must be 0.
# Author: PopZslam@Linux.net
#-----------------------------------
chkUID(){
getUID(){
  id|sed -e 's/(.*$//' -e 's/^uid=//'
}

if [ "`getUID`" -ne 0 ]
then
  echo -e "\tYou are not root!"
  exit 0
fi
}
chkUID
usagePRT(){
  echo ${USAGE:='USAGE:' `basename $0` '-f namelistfile'}
}
chkFILE(){
if [ ! -z "`awk 'NF!=2{print NF;exit;}' $1`" ] && [ "`awk 'NF!=2{print NF;exit;}' $1`" -ne 2 ] ; then
  echo -e "The file's format is not right!"
  exit 0
fi
}

userCHK(){
for USER in `awk '{print $1;}' $1`
do
  if grep -wq $USER /etc/passwd ; then
    echo -e "The user($USER) has been added!"
    exit 1
  fi
  if echo $USER|grep -wq "^[0-9].*" ; then
    echo -e "The user($USER)'s name is wrong format!"
    exit 1
  fi
done
}

setOPT(){
echo -e "Now Let's set some options or you can use default settings."
setGRPNAME(){
while :
do
  echo -e "Would you like to add a new group to add these users to it?"
  echo -e "Enter YES to create a new group otherwise you must verify the group."
  printf "Your Answer: "
  read grpopt
  case $grpopt in
  yes)
    printf "Please enter the group's name: "
    read grpoptnew
    if cat /etc/group|sed 's/:.*//'|grep -wq $grpoptnew ; then
      echo "The group's name($grpoptnew) exist."
      exit
    else
      grpname=$grpoptnew
      echo -e "All these users will be added to group($grpname)..."
      echo -e "Adding group ..."
      if cp /etc/group /etc/group.$$ > /dev/null 2>&1 ; then
        if groupadd $grpname ; then
          echo -e "The group($grpname) is added!"
          rm -f /etc/group.$$
          break 1
        else
          echo -e "There's something wrong when adding the group($grpname)."
          echo -e " *** Please recovered the group file. *** "
          echo -e "You can cp /etc/group.$$ to /etc/group to recover."
        fi
      else
        echo "Error! Please check the program or your disk space."
        exit 0
      fi
    fi
    ;;
  *) : ;;
  esac
done
}
setGRPNAME
}

addUSER(){
if cp /etc/passwd /etc/passwd.$$ && cp /etc/shadow /etc/shadow.$$ ; then
  for user in `sed 's/ .*//' $1`
  do
    pass=`awk '{
    $1~/$name/
    {print $2;exit}
    } name=$user' $1`
    if [ -z "$pass" ] ; then
      echo -e "The passwd is used by default sun123."
      pass=sun123
    fi
    if [ ${#pass} -lt 6 ] ; then
      echo -e "The user($user)'s password is too short!"
      echo -e "Use default password: sun123."
      pass=sun123
    fi
    if useradd $user ; then
      echo -e "The user($user) is added."
      if echo $pass|passwd $user --stdin > /dev/null 2>&1 ; then
        echo -e "The user($user)'s password is setted!"
      else
        echo -e "The user($user)'s password is NOT set!"
      fi
    else
      echo -e "The user($user) is NOT add."
    fi
  done
  rm -f /etc/passwd.$$ /etc/shadow.$$
else
  echo -e "There something wrong when backup the passwd and shadow file."
fi
}

if [ $# -ne 2 ] ; then
  usagePRT
  exit 0
fi

case "$1" in
-f)
  if [ -f "$2" ] ; then
    echo -e "Reading usernamelist file""("$2")" "..."
    chkFILE $2
    userCHK $2
    setOPT
    addUSER $2
  else
    echo -e "There's no usernamelist file!"
  fi
  ;;
*) usagePRT
  exit 0
  ;;
esac


附:获取不同操作系统下的IP地址

#!/bin/sh
# Shell script scripts to read ip address
# -------------------------------------------------------------------------
# Copyright (c) 2005 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
# Get OS name
OS=`uname`
IO="" # store IP
case $OS in
Linux) IP=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'`;;
FreeBSD|OpenBSD) IP=`ifconfig | grep -E 'inet.[0-9]' | grep -v '127.0.0.1' | awk '{ print $2}'` ;;
SunOS) IP=`ifconfig -a | grep inet | grep -v '127.0.0.1' | awk '{ print $2} '` ;;
*) IP="Unknown";;
esac
echo "$IP"

练习:

有数据文件内容如下:

Mike Harrington:(510) 548-1278:250:100:175
Chrstian Dobbins:(408) 538-2358:155:90:201
Susan Dalsass:(206) 548-1348:250:60:50
Archie McNichol:(206) 654-6279:250:100:175
Jody Savage:(206) 548-1278:15:188:150
Guy Quigley:(916) 343-6410:250:100:175
Dan Savage:(406) 298-7744:450:300:275
Nancy McNeil:(206) 548-1278:250:80:75
John Goldenrod:(916) 348-4278:250:100:175
Chet Main:(510) 548-5258:50:95:135
Tom Savage:(408) 926-3456:250:168:200
Elizabeth Stachelin:(916) 440-1763:175:75:300

各行记录内容包括姓名、电话号码和最近3个月的捐款数额。

针对上述文件,使用gawk完成下列操作:

1. 打印所有电话号码

2. 打印Dan的电话号码

3. 打印Susan的姓名和电话号码

4. 打印所有以D开头的姓( gawk -F: '/^D/ {split($1,name," ");print name[2]}' datafile)

5. 打印所有以C或E开头的名

6. 打印所有只有4个字母的姓

7. 打印所有916区的人的姓

8. 打印Mike的捐款数额,打印时每个值都要以美元符号开头.

9. 先打印姓,然后打印一个逗号,再打印名

10. 写下一个名为facts的awk脚本,完成以下操作:打印Savages的全名和电话号码;打印Chet的捐款数额;打印所有第一个月捐款250元的人.

11. 打印在第一个月捐款超过100元的人的姓名。

12. 打印在第一个月捐款少于60元的人的姓名和电话号码。

13. 打印在第三个月捐款额在90元到150元之间的人。

14. 打印在这三个月捐款总额超过800元的人。

15. 打印不在916区的人的姓.

16. 打印月均捐款额大于150元的人的姓名和电话号码.

17. 打印每条记录,并在记录前加上其记录号

18. 打印每个人的姓名和捐款总额

19. 把Elizabeth第二个月的捐款额加上10

20. 把Nancy McNeil的名字改成Louise McInnes

21. 编写一个用户自定义函数,要求函数能返回指定月份的人均捐款数额,月份由命令行传入.

22. 编写一个gawk程序对文件中的每行编号,然后将它的输出发送到标准输出.

23. 编写一个gawk程序,显示第1个字段中的字符数目,及第一个字段的内容.

24.使用gawk来判断/etc/termcap中有多少行包含了字符串vt100.并使用grep验证一下自己的程序.

参考答案:

1. 打印所有电话号码

gawk -F: '{ print $2; }' awk2.sh

gawk -F: '{ printf("%s\n", $2); }' awk2.sh

2. 打印Dan的电话号码

gawk -F: '/Dan/{ print $2; }' awk2.sh

3. 打印Susan的姓名和电话号码

gawk -F: '/Susan/{ print $1,$2; }' awk2.sh

4. 打印所有以D开头的姓

gawk '{printf("%s %s\n", $1,$2)}' awk2.sh | gawk '$2~/^D/{print $2}'

5. 打印所有以C或E开头的名

gawk '$1~/^[CE]/{print $1}' awk2.sh

6. 打印所有只有4个字母的姓

gawk -F: '{print $1}' awk2.sh | gawk '$2 ~/^....$/{print $2}'

7. 打印所有916区的人的姓

gawk -F: '$2~/(916)/ {split($1,x," ");print x[2]}' datafile
或:
gawk -F: '$2~/(916)/ {print $1}' datafile | gawk '{print $2}'

8. 打印Mike的捐款数额,打印时每个值都要以美元符号开头.

gawk -F: '$1~/Mike/ {printf("$%d,$%d,$%d\n", $3,$4,$5)}' datafile

9. 先打印姓,然后打印一个逗号,再打印名

gawk -F: 'split($1,x," ") {printf("%s,%s\n",x[2],x[1])}' datafile

10. 写下一个名为facts的awk脚本,完成以下操作:打印Savages的全名和电话号码;打印Chet的捐款数额;打印所有第一个月捐款250元的人.

脚本的facts内容如下:

BEGIN{
FS=":"
}

$1 ~ /Savages/ {print $1,$2}
$1 ~ /Chen/ {print $1,$3,$4,$5}
$3==250 {print $1,$2}

按下面的方式执行脚本

gawk -f facts datafile

11. 打印在第一个月捐款超过100元的人的姓名。

gawk -F: '$3>100{print $1}' awk2.sh

12. 打印在第一个月捐款少于60元的人的姓名和电话号码。

gawk -F: '$3<60 {print $1,$2}' awk2.sh

13. 打印在第三个月捐款额在90元到150元之间的人。

gawk -F: '90<=$5 && $5<=150 {print $1}' awk2.sh

14. 打印在这三个月捐款总额超过800元的人。

gawk -F: '$3+$4+$5>800 {print $1}' awk2.sh

15. 打印不在916区的人的姓.

gawk -F: '$2!~916 {split($1,nn," "); print nn[2]}' datafile

gawk -F: '$2!~916 {print $1}' datafile | gawk '{print $2}'

16. 打印月均捐款额大于150元的人的姓名和电话号码.

gawk -F: '$3+$5+$4>450 {print $1,$2}' datafile

17. 打印每条记录,并在记录前加上其记录号

gawk '{print NR" "$0}' awk2.sh

18. 打印每个人的姓名和捐款总额

gawk -F: '{print $1,$3+$4+$5;}' awk2.sh

19. 把Elizabeth第二个月的捐款额加上10

gawk '$1~/Elizabeth/ {$4=$4+10;print $0;}' datafile

20. 把Nancy McNeil的名字改成Louise McInnes

gawk -F: '$1 ~ /Nancy McNeil/{gsub("Nancy McNeil","Louise McInnes",$1);print}' awk2.sh

21. 编写一个用户自定义函数,要求函数能返回指定月份的人均捐款数额,月份由命令行传入.

脚本应按如下方式执行:

gawk -f awk3.sh -v m=0 awk2.sh

脚本awk3的内容如下:

BEGIN{
FS=":"
r=0
n=0
}

function mon_tot(curmonth)
{
r+=$(2+m)
n++
return r
}

x=mon_tot(m){}

END{
printf("month%d:average denotion is %s\n",m, x/n)
}

22. 编写一个gawk程序对文件中的每行编号,然后将它的输出发送到标准输出.

gawk '{print NR" "$0}' awk2.sh

23. 编写一个gawk程序,显示第1个字段中的字符数目,及第一个字段的内容.

gawk -F: '{print length($1),$1}' awk2.sh

24.使用gawk来判断/etc/termcap中有多少行包含了字符串vt100.并使用grep验证一下自己的程序.

gawk 'BEGIN{n=0} /vt100/{n++} END{print n}' /etc/termcap

grep -c vt100 /etc/termcap