zoukankan      html  css  js  c++  java
  • awk sed 总结

    Awk总结笔记

    介绍

    90年代 new awk :nawk

    Linux 的是gawk 我们简化awk

    用法

    #  awk [options ] ‘scripts’ file1 file2 ....

    # awk [options ] ‘PATTERN {action }’ file1 file2 ....

    读入文本先切片如下 切5片

    每片$n  整行$0

    每行片数不一样

    Print

    内置变量

        以下为awk内置变量:

              ARGC        命令行参数个数

              FILENAME    当前输入文档的名称

              FNR        当前输入文档的当前记录编号,尤其当有多个输入文档时有用

              NR        输入流的当前记录编号

              NF        当前记录的字段个数

              FS        字段分隔符

              OFS        输出字段分隔符,默认为空格

              ORS        输出记录分隔符,默认为换行符

              RS        输入记录分隔符,默认为换行符

        示例:

    显示第一列字段  第一片

    [root@centos5 awk]# cat a.txt 

    welcome to my heart

    i am liujianzuo 

    how are u?

    [root@centos5 awk]# awk '{print $1}' a.txt 

    welcome

    i

    How

    [root@centos5 awk]# df -hP  #显示到一行

    Filesystem            Size  Used Avail Use% Mounted on

    /dev/sda3             7.1G  3.2G  3.6G  48% /

    /dev/sda1             198M   13M  176M   7% /boot

    tmpfs                  63M     0   63M   0% /dev/shm

    /dev/sdb1              99M  6.1M   88M   7% /data

    [root@centos5 awk]# df -h|awk '{print $1}'       

    Filesystem

    /dev/sda3

    /dev/sda1

    tmpfs

    /dev/sdb1

    -F 指定分隔符

    类似cut -d

    [root@centos5 awk]# awk -F : '{print $1}' /etc/passwd 

    root

    bin

    daemon

    adm

    lp

    sync

    shutdown

    halt

    mail

    news

    uucp

    operator

    games

    gopher

    ftp

    nobody

    nscd

    vcsa

    pcap

    ntp

    dbus

    如果你的列数不一致 怎么取左后一列 $NF

    [root@centos5 awk]# awk -F : '{print $NF}' /etc/passwd 

    /bin/bash

    /sbin/nologin

    /sbin/nologin

    /sbin/nologin

    /sbin/nologin

    /bin/sync

    /sbin/shutdown

    /sbin/halt

    /sbin/nologin

    /sbin/nologin

    /sbin/nologin

    /sbin/nologin

    打印倒数第2字段 将NF做数学运算

    [root@centos5 awk]# cat a.txt 

    welcome to my heart

    i am liujianzuo 

    how are u?

    [root@centos5 awk]# awk '{print $(NF-2)}' a.txt  

    to

    i

    how

    -F 改变分隔符 FS字段分隔符读入的时候也能实现

    [root@centos5 awk]# awk -v FS=: '{print $NF}' /etc/passwd|tail -3   

    /sbin/nologin

    /bin/bash

    /bin/bash

    输出的分隔符 OFS 默认是逗号分开变量,输出空格的

    [root@centos5 awk]# awk '{print $1 $2}' a.txt                       

    welcometo

    iam

    howare

    [root@centos5 awk]# awk '{print $1,$2}' a.txt  

    welcome to

    i am

    how are

    [root@centos5 awk]# awk -v OFS=: '{print $1,$2}' a.txt   

    welcome:to

    i:am

    how:are

    Printf

    字符串个数%s 双引号引起来

    不会自动换行 需要

    格式符候还可以加修饰符

    如下是每一行开始第一列字段是10个字符对其,第二列字段是1个字符对其,默认右对齐

    ,不会自动换行

    [root@centos5 awk]# awk '{printf "%10s,%s",$1,$2}' a.txt  

       welcome,to         i,am       how,are[root@centos5 awk]# 

    让其换行

    [root@centos5 awk]# awk '{printf "%10s,%s ",$1,$2}' a.txt 

       welcome,to

             i,am

           how,are

    输出左对齐 修饰符 -

    [root@centos5 awk]# awk '{printf "%-10s,%-s ",$1,$2}' a.txt 

    welcome   ,to

    i         ,am

    how       ,are

    格式之间的符号会输出,不需要写

    [root@centos5 awk]# awk '{printf "%-10s%-s ",$1,$2}' a.txt  

    welcome   to

    i         am

    how       are

    print输出重定向

    将print 打印结果输出

    [root@centos5 awk]# awk -F : '{printf "%-10s %i ",$1,$3 > "/dev/stderr" }' /etc/passwd   #改变输出流,引号引起来

    [root@centos5 awk]# awk -F : '{printf "%-10s %i ",$1,$3 > "/server/scripts/awk/passwd.log" }' /etc/passwd     #改变输出流          

    [root@centos5 awk]# cat passwd.log  

    root       0

    bin        1

    daemon     2

    adm        3

    lp         4

    sync       5

    shutdown   6

    halt       7

    mail       8

    news       9

    uucp       10

    operator   11

    games      12

    gopher     13

    ftp        14

    nobody     99

    nscd       28

    vcsa       69

    pcap       77

    ntp        38

    dbus       81

    avahi      70

    rpc        32

    mailnull   47

    smmsp      51

    oprofile   16

    sshd       74

    rpcuser    29

    nfsnobody  65534

    xfs        43

    haldaemon  68

    avahi-autoipd 100

    oldboy     500

    mysql      501

    nginx      502

    nagios     503

    disdata    999

    ayibang    1000

    Awk的操作符

    正则匹配=应该用[=]

    这里y是种模式

    第三个字符串操作符实例

    [root@centos5 awk]# awk 'BEGIN{print "a" "b"}'        

    ab

    第五个模式匹配

    匹配某一行第一个字段是以root开头的模式我们就打印第3 4 最后一个字段

    [root@centos5 awk]# awk -F : '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd

    0 0 /bin/bash

    Awk的模式

    正则表达式 模式+动作

    awk正则表达式使用外部变量

     

    awk的正则表达式匹配中,如果要使用外部shell
    变量,先在变量外加双引号,再加单引号即可,如:

    for i in read write print; 

    do 

    cat file.txt | awk '{ if ($7~/'"$i"'/) {print $0} }'| wc -l ; 

    done

    匹配pation之后是动作如下例子,匹配bash这个模式后动作是打印匹配的包含的全部

    # awk [options ] 'PATTERN {action }' file1 file2 ....

    [root@centos5 awk]# awk -F : '/bash/ {print $0}' /etc/passwd        root:x:0:0:root:/root:/bin/bash

    oldboy:x:500:500::/home/oldboy:/bin/bash

    disdata:x:999:999::/home/disdata:/bin/bash

    ayibang:x:1000:1000::/home/ayibang:/bin/bash

    [root@centos5 awk]# awk -F : '/bash/ {print $1}' /etc/passwd 

    root

    oldboy

    disdata

    ayibang

    表达式

    [root@centos5 awk]# awk -F : '$3 >= 500 {print $1}' /etc/passwd     

    nfsnobody

    oldboy

    mysql

    nginx

    nagios

    disdata

    ayibang

    [root@centos5 awk]# awk -F : '$3 >= 500 {print $1,$3}' /etc/passwd

    nfsnobody 65534

    oldboy 500

    mysql 501

    nginx 502

    nagios 503

    disdata 999

    ayibang 1000

    匹配指定范围 的模式

    /bash/,/500/

    [root@centos5 ceshi]# awk '/bash|500/ {print $0}' /etc/passwd

    root:x:0:0:root:/root:/bin/bash

    oldboy:x:500:500::/home/oldboy:/bin/bash

    disdata:x:999:999::/home/disdata:/bin/bash

    ayibang:x:1000:1000::/home/ayibang:/bin/bash

    liujianzuo:x:1001:1001::/home/liujianzuo:/bin/bash

    Begin end 特殊模式

    [root@centos5 ~]# awk -F: '$3>=500 {print "USERNAME       UID";printf "%-15s%s ",$1,$3}' /etc/passwd    #在awk预读每一行的时候,都打印一行

    USERNAME       UID

    nfsnobody      65534

    USERNAME       UID

    oldboy         500

    USERNAME       UID

    mysql          501

    USERNAME       UID

    nginx          502

    USERNAME       UID

    nagios         503

    USERNAME       UID

    disdata        999

    USERNAME       UID

    ayibang        1000

    [root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} $3 >= 500 {printf "%-15s%s ",$1,$3}' /etc/passwd 

    USERNAME       UID

    nfsnobody      65534

    oldboy         500

    mysql          501

    nginx          502

    nagios         503

    disdata        999

    ayibang        1000

    liujianzuo     1001

    [root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} {if($3 >= 500) printf "%-15s%s ",$1,$3}' /etc/passwd

    USERNAME       UID

    nfsnobody      65534

    oldboy         500

    mysql          501

    nginx          502

    nagios         503

    disdata        999

    ayibang        1000

    liujianzuo     1001

    [root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"}{printf "%-15s%s ",$1,$3}' /etc/passwd 

    USERNAME       UID

    root           0

    bin            1

    daemon         2

    adm            3

    lp             4

    sync           5

    shutdown       6

    halt           7

    mail           8

    news           9

    uucp           10

    operator       11

    games          12

    gopher         13

    ftp            14

    nobody         99

    nscd           28

    vcsa           69

    pcap           77

    ntp            38

    dbus           81

    avahi          70

    rpc            32

    mailnull       47

    smmsp          51

    oprofile       16

    sshd           74

    rpcuser        29

    nfsnobody      65534

    xfs            43

    haldaemon      68

    avahi-autoipd  100

    oldboy         500

    mysql          501

    nginx          502

    nagios         503

    disdata        999

    ayibang        1000

    liujianzuo     1001

    End应用 添加表尾

    [root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME       UID"} {$3>=500;printf "%-15s%s ",$1,$3}END{printsswd "END"}' /etc/passwd          

    USERNAME       UID

    root           0

    bin            1

    daemon         2

    adm            3

    lp             4

    sync           5

    shutdown       6

    halt           7

    mail           8

    news           9

    uucp           10

    operator       11

    games          12

    gopher         13

    ftp            14

    nobody         99

    nscd           28

    vcsa           69

    pcap           77

    ntp            38

    dbus           81

    avahi          70

    rpc            32

    mailnull       47

    smmsp          51

    oprofile       16

    sshd           74

    rpcuser        29

    nfsnobody      65534

    xfs            43

    haldaemon      68

    avahi-autoipd  100

    oldboy         500

    mysql          501

    nginx          502

    nagios         503

    disdata        999

    ayibang        1000

    liujianzuo     1001

    END

    BEGIN 赋值

    [root@centos5 ceshi]# awk -F : '{print $1}' /etc/passwd |head -1

    root

    [root@centos5 ceshi]# awk -v FS=: '{print $1}' /etc/passwd |head -1

    root

    [root@centos5 ceshi]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd |head -1           

    root

    控制语句

    如果if后面是好几个条件应该用花括号扩起来

    If案例

    [root@centos5 ~]# awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd

    8

    [root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd 

    /sbin/nologin

    /bin/bash

    /sbin/nologin

    /sbin/nologin

    /sbin/nologin

    /bin/bash

    /bin/bash

    /bin/bash

    [root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd|wc -l

    8

    [root@centos5 ceshi]# awk -F: '{if ($3 == 0) print $1,"Admin";else print $1,"Comman user"}' /etc/passwd

    root Admin

    bin Comman user

    daemon Comman user

    adm Comman user

    lp Comman user

    sync Comman user

    shutdown Comman user

    halt Comman user

    mail Comman user

    news Comman user

    uucp Comman user

    operator Comman user

    games Comman user

    gopher Comman user

    ftp Comman user

    nobody Comman user

    nscd Comman user

    vcsa Comman user

    pcap Comman user

    ntp Comman user

    dbus Comman user

    avahi Comman user

    rpc Comman user

    mailnull Comman user

    smmsp Comman user

    oprofile Comman user

    sshd Comman user

    rpcuser Comman user

    nfsnobody Comman user

    xfs Comman user

    haldaemon Comman user

    avahi-autoipd Comman user

    oldboy Comman user

    mysql Comman user

    nginx Comman user

    nagios Comman user

    disdata Comman user

    ayibang Comman user

    liujianzuo Comman user

    While案例

    [root@centos5 ~]# awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd  

    root

    x

    0

    bin

    x

    1

    daemon

    x

    2

    adm

    x

    3

    lp

    x

    4

    sync

    x

    5

    shutdown

    x

    6

    halt

    x

    7

    mail

    x

    8

    news

    x

    9

    uucp

    x

    10

    operator

    x

    11

    games

    x

    12

    gopher

    x

    13

    ftp

    x

    14

    nobody

    x

    99

    nscd

    x

    28

    vcsa

    x

    69

    pcap

    x

    77

    ntp

    x

    38

    dbus

    x

    81

    avahi

    x

    70

    rpc

    x

    32

    mailnull

    x

    47

    smmsp

    x

    51

    oprofile

    x

    16

    sshd

    x

    74

    rpcuser

    x

    29

    nfsnobody

    x

    65534

    xfs

    x

    43

    haldaemon

    x

    68

    avahi-autoipd

    x

    100

    oldboy

    x

    500

    mysql

    x

    501

    nginx

    x

    502

    nagios

    x

    503

    disdata

    x

    999

    ayibang

    x

    1000

    liujianzuo

    x

    1001

    Awk可以加pattion 模式的意思,如果不匹配pattion意指其会每行都匹配。

    [oldboy@centos5 ~]$ awk -F: '$1 !~ /^root/{i=1;while (i<=2) {print $i;i++}}' /etc/passwd

    bin

    x

    daemon

    x

    adm

    x

    lp

    x

    sync

    x

    shutdown

    x

    halt

    x

    mail

    x

    news

    x

    uucp

    x

    operator

    x

    games

    x

    gopher

    x

    ftp

    x

    nobody

    x

    nscd

    x

    vcsa

    x

    pcap

    x

    ntp

    x

    dbus

    x

    avahi

    x

    rpc

    x

    mailnull

    x

    smmsp

    x

    oprofile

    x

    sshd

    x

    rpcuser

    x

    nfsnobody

    x

    xfs

    x

    haldaemon

    x

    avahi-autoipd

    x

    oldboy

    x

    mysql

    x

    nginx

    x

    nagios

    x

    disdata

    x

    ayibang

    x

    liujianzuo

    X

    例如我想取第第奇数个字段。我们递增i+=2即可

    [oldboy@centos5 ~]$ awk -F: '$3 >= 500{i=1;while (i<=4) {print $i;i+=2}}' /etc/passwd            

    Nfsnobody  #第一列

    65534   #第三列

    Oldboy #第一列

    500  #第三列

    mysql

    501

    nginx

    502

    nagios

    503

    disdata

    999

    ayibang

    1000

    liujianzuo

    1001

    do-while 无论条件如何,首先会循环一遍,当条件一满足就会退出

    用awk的while循环计算1+。。。+100

    [root@centos5 awk]# awk 'BEGIN{i=1;while (i<=100) {sum+=i;print sum;i++}}' |tail -1

    5050

    awk 'BEGIN{i=1;do {sum+=i;print sum;i++}while(i<=100)}'|tail -1

    5050

    awk 'BEGIN{i=1;do {sum=sum+i;print sum;i++}while(i<=100)}'|tail -1  

    5050

    awk 'BEGIN{i=1;do {sum+=i;i++}while(i<=100) print sum}' 

    【元婴】北京-吴兆 2015/1/11 17:53:30

    循环中不输出,最后输出结构就行了…… 

    For循环案例

    cat filename | nawk -F " "  '{for (i=4;i<=NF;i++)printf("%s ", $i);print ""}'  字段不换行 printf

    [root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=NF;i+=2) print $i}' /etc/passwd 

    awk -F: '$3>=500{for (i=1;i<=NF;i+=2) printf("%s ", $i);print ""}' /etc/passwd 

    nfsnobody

    65534

    Anonymous NFS User

    /sbin/nologin

    oldboy

    500

    /bin/bash

    mysql

    501

    /sbin/nologin

    nginx

    502

    /sbin/nologin

    nagios

    503

    /sbin/nologin

    disdata

    999

    /bin/bash

    ayibang

    1000

    /bin/bash

    liujianzuo

    1001

    /bin/bash

    for打印第奇数个字段

    [root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=5;i+=2) print $i}' /etc/passwd  

    nfsnobody

    65534

    Anonymous NFS User

    oldboy

    500

    mysql

    501

    nginx

    502

    nagios

    503

    disdata

    999

    ayibang

    1000

    liujianzuo

    1001

    Awk 的For循环的1加到100

    [root@centos5 awk]# awk 'BEGIN{for (i=i;i<=100;i++) {j=j+i;print j}}'|tail -1

    5050

    [root@ayibang-server /server/scripts]# awk 'BEGIN{j=0;for (i=1;i<=100;i++) j+=i;{print j}}'
    5050

    Awk的内置变量

    内置变量

        以下为awk内置变量:

              ARGC        命令行参数个数

              FILENAME    当前输入文档的名称

              FNR        当前输入文档的当前记录编号,尤其当有多个输入文档时有用

              NR        输入流的当前记录编号

              NF        当前记录的字段个数

              FS        字段分隔符

              OFS        输出字段分隔符,默认为空格

              ORS        输出记录分隔符,默认为换行符

              RS        输入记录分隔符,默认为换行符

    示例:

    Awk的引用shell中的参数

    [liujianzuo@w2 scripts]$  for n in {06..26};do for i in `ls -l /data1/logs/qr* |awk '{print $NF}'`;do wc -l $i|awk -F . '$NF ~ /201507'${n}'/{print $0}';done;done                                  1 /data1/logs/qrscene_51pro_gz.log.20150707

    6 /data1/logs/qrscene_51pro_hz.log.20150707

    2 /data1/logs/qrscene_51pro_nj.log.20150707

    3 /data1/logs/qrscene_51pro_qd.log.20150707

    1 /data1/logs/qrscene_51pro_sh.log.20150707

    6 /data1/logs/qrscene_51pro_wh.log.20150707

    1 /data1/logs/qrscene_51pro_xa.log.20150707

    1 /data1/logs/qrscene_51pro_zz.log.20150707

    4 /data1/logs/qrscene_cq_dm.log.20150707

    5 /data1/logs/qrscene_cq_sl.log.20150707

    17 /data1/logs/qrscene_cs_dm.log.20150707

    1 /data1/logs/qrscene_gz_dm.log.20150707

    1 /data1/logs/qrscene_gz_szi.log.20150707

    6 /data1/logs/qrscene_hz_dm.log.20150707

    9 /data1/logs/qrscene_mlyh.log.20150707

    2 /data1/logs/qrscene_nj_dm.log.20150707

    3 /data1/logs/qrscene_nj_sl.log.20150707

    1 /data1/logs/qrscene_qd_szi.log.20150707

    1 /data1/logs/qrscene_xa_szi.log.20150707

    14 /data1/logs/qrscene_xiaomi.log.20150707

    26 /data1/logs/qrscene_xz.log.20150707

    4 /data1/logs/qrscene_zz_dm.log.20150707

    3 /data1/logs/qrscene_15suit.log.20150708

    5 /data1/logs/qrscene_51pro_bj.log.20150708

    1 /data1/logs/qrscene_51pro_gz.log.20150708

    5 /data1/logs/qrscene_51pro_hz.log.20150708

    19 /data1/logs/qrscene_51pro_qd.log.20150708

    1 /data1/logs/qrscene_51pro_wh.log.20150708

    。。。。。略去n行

    http://oldboy.blog.51cto.com/2561410/760192 

    问题为:

    4)已知:/etc/hosts的内容为

    192.168.1.11  oldboy11.etiantian.org

    192.168.1.21  oldboy21.etiantian.org

    192.168.1.31  oldboy31.etiantian.org

    #192.168.1.111  oldboy111.etiantian.org

    请用shell脚本实现,怎么才能在输入IP后找到/etc/hosts里对应的唯一的hostname?

    解答:

    法1)脚本过滤法

    [root@old_boy scripts]# cat judgehost.sh   

    #!/bin/bash  

    echo "please input ip address:" 

    read ip  

    [ -n "`grep "$ip " /etc/hosts`" ] &&   #注意前面的过滤条件结尾带有空格。  

    echo "The hostname is: `grep "$ip " /etc/hosts |awk '{print $2}'`" ||   

    echo "The ip is invalid" 

     提示:

    1)这是一个grep过滤加条件判断的实现语法:

    2)条件判断语法为[ -n "ddd" ] && echo 1 || echo 0

    3)[ -n "`grep "$ip " /etc/hosts`" ] &&   #注意前面的过滤条件结尾带有空格。这里啊,是为了排除下面的重复情况

     192.168.1.11  oldboy11.etiantian.org

     192.168.1.111  oldboy111.etiantian.org

    ----------------我是每种方法分隔符---------------

    法2)脚本精确匹配法:

    #!/bin/bash  

    #author oldboy  

    #qq 31333741  

    #judge input  

    if [ $# -ne 1 ]  

      then 

        echo "input error!" 

        exit 1  

    fi  

    flag=0  

    exec < /etc/hosts  

    while read line  

    do  

     if [ "$1" = "`echo $line|awk '{print $1}'`" ]  

       then 

           flag=1  

           echo "the $1 's hostname is `echo $line|awk '{print $2}'`"   

           break;  

     fi  

    done   

    [ $flag -eq 0 ] && echo " sorrry,not find $1 's hostname!" 

    提示:此题,请大家学习while的用法及设置flag的思路。

    执行结果:

    [root@old_boy scripts]# sh oldboy.sh 192.168.1.11

    the 192.168.1.11 's hostname is oldboy11.etiantian.org

    [root@old_boy scripts]# sh oldboy.sh 192.168.1.21

    the 192.168.1.21 's hostname is oldboy21.etiantian.org

    [root@old_boy scripts]# sh oldboy.sh 192.168.1.311

     sorrry,not find 192.168.1.311 's hostname!

    ----------------我是每种方法分隔符---------------

    特别提示:下面的方法中,老男孩老师大量的使用了awk的不同方法来实现同样的功能,来告诉大家,awk是很强大的, 希望同学们能按照老师的教学要求精通之。

    法3)awk精确匹配:

    准备:

    [root@old_boy scripts]# tail -4 /etc/hosts

    192.168.1.11  oldboy11.etiantian.org

    192.168.1.111  oldboy111.etiantian.org

    192.168.1.21  oldboy21.etiantian.org

    192.168.1.31  oldboy31.etiantian.org

    脚本:

    [root@old_boy scripts]# cat awkhost1.sh   

    awk 'BEGIN {a="'$1'"} {if($1==a) print $2; }' /etc/hosts  

    执行结果:

    [root@old_boy scripts]# sh awkhost1.sh 192.168.1.21

    oldboy21.etiantian.org

    [root@old_boy scripts]# sh awkhost1.sh 192.168.1.31

    oldboy31.etiantian.org

    [root@old_boy scripts]# sh awkhost1.sh 192.168.1.11

    oldboy11.etiantian.org

    提示:注意a="'$1'"的用法,$1为命令行传参。awk程序中调用系统变量的方法a="'$1'"。

    ----------------我是每种方法分隔符---------------

    法4)awk精确匹配法

    [root@old_boy scripts]# cat awkhost2.sh   

    awk '{if($1=="'$1'") print $2}' /etc/hosts  

    执行结果:

    [root@old_boy scripts]# awkhost2.sh 192.168.1.11

    oldboy11.etiantian.org

    [root@old_boy scripts]# awkhost2.sh 192.168.1.21

    oldboy21.etiantian.org

    [root@old_boy scripts]# awkhost2.sh 192.168.1.311

    ----------------我是每种方法分隔符---------------

    法5)awk过滤法

    [root@old_boy scripts]# cat awkhost4.sh   

    awk '/'"${1} "'/''{print $2}' /etc/hosts  

    执行结果:  

    [root@old_boy scripts]# awkhost4.sh 192.168.1.21  

    oldboy21.etiantian.org  

    [root@old_boy scripts]# awkhost4.sh 192.168.1.11  

    oldboy11.etiantian.org  

    [root@old_boy scripts]# awkhost4.sh 192.168.1.31  

    oldboy31.etiantian.org  

    提示:除了语法外,这道题有个学问,就是过滤时传参结尾要带个空格,这样才能过滤重复IP的情况  

    如:  

     192.168.1.11  oldboy11.etiantian.org  

     192.168.1.111  oldboy111.etiantian.org 

    ----------------我是每种方法分隔符---------------

    法6)awk过滤法

    [root@old_boy scripts]# cat awkhost5.sh   

    awk '{if($1~/'$1'/) print $2}'  /etc/hosts ##如果文件第一列包含命令行第一个参数字符则打印第二列  

    执行结果:  

    [root@old_boy scripts]# awkhost5.sh 192.168.1.31  

    oldboy31.etiantian.org  

    [root@old_boy scripts]# awkhost5.sh 192.168.1.11  

    oldboy11.etiantian.org  

    oldboy111.etiantian.org ------>这里有bug了。  

    [root@old_boy scripts]# awkhost5.sh 192.168.1.21  

    oldboy21.etiantian.org  

    改进下来排除bug:  

    [root@old_boy scripts]# cat awkhost5-1.sh   

    awk '{if($1~/'$1' /) print $2}'  /etc/hosts ==>用上面加空格的思路不对。  

    [root@old_boy scripts]# cat awkhost5-1.sh   

    awk '{if($1~/'$1'$/) print $2}'  /etc/hosts #增加一个正则表达式$  

    执行结果:  

    [root@old_boy scripts]# awkhost5-1.sh 192.168.1.21  

    oldboy21.etiantian.org  

    [root@old_boy scripts]# awkhost5-1.sh 192.168.1.11  

    oldboy11.etiantian.org  

    [root@old_boy scripts]# awkhost5-1.sh 192.168.1.31  

    oldboy31.etiantian.org 

    ----------------我是每种方法分隔符---------------

    法7)awk -v精确匹配法

    命令行测试:  

    [root@old_boy scripts]# awk -v p=192.168.1.21 '$1 == p{print $2}' /etc/hosts  

    oldboy21.etiantian.org  

    [root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p{print $2}' /etc/hosts  

    oldboy11.etiantian.org  

    [root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p {print $2}' /etc/hosts  

    oldboy11.etiantian.org  

    实际脚本: 

    [root@old_boy scripts]# cat awkhost6.sh   

    #!/bin/bash  

    #p=$1  

    #awk -v p="$p" '$1 == p{print $2}' /etc/hosts  

    awk -v p="$1" '$1 == p{print $2}' /etc/hosts 

    执行结果:

    [root@old_boy scripts]# sh  awkhost6.sh  192.168.1.11

    oldboy11.etiantian.org

    [root@old_boy scripts]# sh  awkhost6.sh  192.168.1.21

    oldboy21.etiantian.org

    提示:

    1)传参非awk程序,因此写法p="$1"

    2)man awk

           -v var=val

           --assign var=val

                  Assign the value val to the variable var, before execution of the program begins.   Such  vari-

                  able values are available to the BEGIN block of an AWK program.

    ----------------我是每种方法分隔符---------------

    法8:精确匹配简单的写法

    [root@old_boy scripts]# cat awkhost9.sh   

    awk  '$1 == "'$1'" {print $2}' /etc/hosts  

    执行结果:  

    [root@old_boy scripts]# sh awkhost9.sh  192.168.1.11  

    oldboy11.etiantian.org  

    [root@old_boy scripts]# sh awkhost9.sh  192.168.1.21  

    oldboy21.etiantian.org  

    [root@old_boy scripts]# sh awkhost9.sh  192.168.1.31  

    oldboy31.etiantian.org  

    特别提示:这里老男孩老师大量的使用了awk的不同方法来实现同样的功能,很强大吧,  

    希望同学们能按照老师的教学要求精通之。 

    Awk的 数组

    数组就是变量的即集合体

    Shell中的打印 echo ${A["x"]} 需要${}才能输出变量,而awk则不用

    下标可以是任意字符,但是我们要将字符用引号引起来,以免被误认为变量

    如下

    [root@centos5 ~]# awk 'BEGIN{A[x]='hello';A[y]='world';print A[x]}'

    [root@centos5 ~]# awk 'BEGIN{A["x"]='hello';A["y"]='world';print A[x],A["y"]}'   

    [root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A[x],A["y"]}'    

     world

    [root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A["x"],A["y"]}'

    hello world

    Awk的数组不能跟shell的数组一样,不能一一遍历,它的元素不都是数字,有可能是字符串或者字段

    第二个是for循环是awk的遍历,这里面的ARRAY是数组,A是我们定义的变量是数组的下标数字0 1 2 3 。。。  A保存的是我们数组ARRAY的下标名字

    例如

    [root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";for (B in A) print A[B]}'   #这里的B是定义的变量就是A数组的下标号,我们遍历A数组,打印所有的元素。B保存的是A数组的下标名字                           

    hello

    world

    例一:awk过滤统计tcp连接状态的个数

    Tcp状态有好多种,最后一列,我们用awk实现统计每种状态的连接数 后面有解释

    [root@centos5 ~]# netstat -ant

    Active Internet connections (servers and established)

    Proto Recv-Q Send-Q Local Address               Foreign Address             State      

    tcp        0      0 0.0.0.0:2049                0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:5666                0.0.0.0:*                   LISTEN      

    tcp        0      0 127.0.0.1:199               0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:624                 0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:22929               0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:52113               0.0.0.0:*                   LISTEN      

    tcp        0      0 0.0.0.0:1012                0.0.0.0:*                   LISTEN      

    tcp        0      0 192.168.92.132:52113        192.168.92.1:49262          ESTABLISHED 

    tcp        0      0 :::52113                    :::*                        LISTEN

    解释例子

    Awk的数组组成:数组名字,数组下标,数组元素,数组元素的值。

    S[$NF]++ 意思是我们这个数组S,我们取最后一列作为这个数组的下标,因此这个数组就是S[LISTEN] S[ESTABLISHED],每读取一行,相同元素会叠加

    这里A是数组S的下标名称,而数组S的下标名称是TIME_WAIT  CLOSE_WAIT   FIN_WAIT1  ESTABLISHED  等等。For循环是遍历的这几种,所以A就代表这几个名称,而S[A]则代表数组元素的值

    [ayibang@db2 ~]$ netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for (A in S) print A,S[A]}' 

    TIME_WAIT 1789

    CLOSE_WAIT 38

    FIN_WAIT1 6

    ESTABLISHED 94

    SYN_RECV 3

    LAST_ACK 3

    LISTEN 23

    或者用ss命令取值

    [ayibang@db2 ~]$ ss -ant |awk '{S[$1]++}END{for (A in S) printf "%4s,%4s ",S[A],A}'

       8,LAST-ACK

       3,SYN-RECV

     292,ESTAB

       1,State

       4,FIN-WAIT-1

       3,CLOSING

       8,FIN-WAIT-2

    6469,TIME-WAIT

      41,CLOSE-WAIT

      23,LISTEN

    例二:awk 完成/etc/passwd 取最后一个字段同种shell解释类型的个数,排除空行

    [root@centos5 ~]# awk -F: '$NF!~/^$/{SHELL[$NF]++}END{for(A in SHELL) printf "%16s:%s ",A,SHELL[A]}' /etc/passwd 

      /sbin/shutdown:1

           /bin/bash:5

       /sbin/nologin:30

          /sbin/halt:1

           /bin/sync:1

    例三:查看访问日志ip;

    [root@db2 logs]# awk '{IP[$1]++}END{for (A in IP) printf "%20s:%5s ",A,IP[A]}' access_www.log |sort -rn|head

              223.9.2.89:   37

          223.68.131.168:   31

           223.243.41.89:    1

          223.240.233.91:   34

          223.223.194.23:   50

         223.223.194.215:   16

          223.167.19.183:   65

         223.166.112.132:    1

            223.104.5.30:   69

             223.104.5.2:    2

    Awik的内置函数

    例一 :统计客户端连接80端口的ip个数,netstat 的第五列 (判断黑客攻击的统计)

    split($5,client,":")含义如下

    ه内置函数split 先把第五个字段,以:为分隔符,切割新的字段,保存成client数组,

    IP[client[1]]++}END{for (i in IP){print IP[i],i}}'

    以新的IP数组,client数组第一列为新数组IP下标,最后做做求和,统计个数 

    split是函数  用小括号…………

    [root@db2 ~]# netstat -ant|awk '/:80/{split($5,client,":");IP[client[1]]++}END{for (i in IP){print IP[i],i}}'|sort -rn |head

    10 116.247.112.153

    6 210.22.62.180

    6 123.125.65.237

    5 123.138.215.24

    3 221.237.44.110

    3 111.202.0.53

    3 106.2.195.214

    2 117.79.81.51

    2 101.80.175.17

    2 0.0.0.0

    Awk练习 

    需求:awk实现每一行对应字段的数字相加

    a文件
    11 23
    13 23
    43 56
    b文件
    11 43
    45 455
    32 23


    输出结果如下
    22 66
    58 478
    75 79

    解答:

    awk '{a[FNR]+=$1;b[FNR]+=$2} END{for(i in a){print a[i],b[i]}}' cc1.log cc2.log 

    awk '{n=FNR;a[n]+=$1;b[n]+=$2} END{for(i=1;i<=n;i++){print a[i],b[i]}}' cc1.log cc2.log

    awk '{n=FNR;a[n]+=$1;b[n]+=$2; if(NR > n) print a[n],b[n]}' cc1.log cc2.log   

    awk '{n=FNR;a[n]+=$1;b[n]+=$2} NR > n {print a[n],b[n]}' cc1.log cc2.log

    awk '{if(NR == FNR){a[NR]=$1;b[NR]=$2}else{print $1+a[FNR],$2+b[FNR]}}' cc1.log cc2.log 

    awk 'NR==FNR {a[NR]=$1;b[NR]=$2;next} {print $1+a[FNR],$2+b[FNR]}' cc1.log cc2.log 

    paste cc1.log cc2.log |awk '{print $1+$3,$2+$4}'

    awk 'NR == FNR{a[i]=$1;b[i]=$2;i++} NR>FNR{print $1+a[j],$2+b[j];j++}' cc1.log cc2.log 

    Awk sed 练习

    20150418周末小题

    原始数据:

    17/Apr/2015:09:29:24 +0800

    17/Apr/2015:09:30:26 +0800

    17/Apr/2015:09:31:56 +0800

    18/Apr/2015:09:34:12 +0800

    18/Apr/2015:09:35:23 +0800

    19/Apr/2015:09:23:34 +0800

    19/Apr/2015:09:22:21 +0800

    20/Apr/2015:09:45:22 +0800

    期望结果:

    2015-04-17 09:29:24+0800

    2015-04-17 09:30:26+0800

    2015-04-17 09:31:56+0800

    2015-04-18 09:34:12+0800

    2015-04-18 09:35:23+0800

    2015-04-19 09:23:34+0800

    2015-04-19 09:22:21+0800

    2015-04-20 09:45:22+0800

    解决实践:来自运维21期悠久之翼 群内分享

    [root@web01 ~]# cat oldboy.txt 

    17/Apr/2015:09:29:24 +0800

    17/Apr/2015:09:30:26 +0800

    17/Apr/2015:09:31:56 +0800

    18/Apr/2015:09:34:12 +0800

    18/Apr/2015:09:35:23 +0800

    19/Apr/2015:09:23:34 +0800

    19/Apr/2015:09:22:21 +0800

    20/Apr/2015:09:45:22 +0800

    [root@web01 ~]# awk '{sub(/Apr/,"04");split($0,array,"[/: ]") ;printf("%s-%s-%s %s:%s:%s%s ",array[3],array[2],array[1],array[4],array[5],array[6],array[7])}' oldboy.txt 

    2015-04-17 09:29:24+0800

    2015-04-17 09:30:26+0800

    2015-04-17 09:31:56+0800

    2015-04-18 09:34:12+0800

    2015-04-18 09:35:23+0800

    2015-04-19 09:23:34+0800

    2015-04-19 09:22:21+0800

    2015-04-20 09:45:22+0800

    1. sub函数

    [root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'sub(/-/,"",$4)'

    a b c 201111-22 a:d

    2. gsub函数

    [root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'gsub(/-/,"",$4)'

    a b c 20111122 a:d

    sub函数只实现第一个位置的替换,gsub函数实现全局的替换。

    Split切割是第一列下表是1

    [root@web01 ~]# sed -nr 's#(..)/(...)/(....):(..):(..):(..) (.*)#3-2-1 4:5:67#;s#Apr#04#p' oldboy.txt 

    2015-04-17 09:29:24+0800

    2015-04-17 09:30:26+0800

    2015-04-17 09:31:56+0800

    2015-04-18 09:34:12+0800

    2015-04-18 09:35:23+0800

    2015-04-19 09:23:34+0800

    2015-04-19 09:22:21+0800

    2015-04-20 09:45:22+0800

    . 是一个字符, s是替换  p打印

    Sed 扩展

    在编写shell脚本的过程中,我们经常需要使用sed流编辑器和awk对文本文件进行处理。

    一、什么是sed

        sed 是一种在线编辑器,它一次处理一行内容。sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。

     

    二、sed的处理过程

        sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。

       前面说到sed不会修改文件,那么现在我们可以知道是为什么了?是因为sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。

    补充知识:

        在使用sed的过程中,我们经常会听到“定址”,那么什么是“定址”呢?

        定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。

    1、地址是一个数字,则表示行号;是“$"符号,则表示最后一行。

    例如:

    [plain] view plaincopy

    1. sed -n '3p' datafile   #只打印第三行  

     

    2、只显示指定行范围的文件内容

    例如:

    [plain] view plaincopy

    1. sed -n '100,200p' mysql_slow_query.log  # 只查看文件的第100行到第200行  

     

    3、地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。

    例如:

    [plain] view plaincopy

    1. sed '2,5d' datafile  
    2. #删除第二到第五行  
    3. sed '/My/,/You/d' datafile  
    4. #删除包含"My"的行到包含"You"的行之间的行  
    5. sed '/My/,10d' datafile  
    6. #删除包含"My"的行到第十行的内容  

     

    三、sed命令和选项

    sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。

    1、sed命令

     

     命令

     功能

     a

     在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“”续行

     c

     用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用""续行

     i

     在当前行之前插入文本。多行时除最后一行外,每行末尾需用""续行

     d

     删除行

     h

     把模式空间里的内容复制到暂存缓冲区

     H

     把模式空间里的内容追加到暂存缓冲区

     g

     把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容

     G

     把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面

     l

     列出非打印字符

     p

     打印行

     n

     读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理

     q

     结束或退出sed

     r

     从文件中读取输入行

     !

     对所选行以外的所有行应用命令

     s

     用一个字符串替换另一个

     g

     在行内进行全局替换

     w

     将所选的行写入文件

     x

     交换暂存缓冲区与模式空间的内容

     y

     将字符替换为另一字符(不能对正则表达式使用y命令)

     

    2、sed选项

     

     选项

     功能

     -e

     进行多项编辑,即对输入行应用多条sed命令时使用

     -n

     取消默认的输出

     -f

     指定sed脚本的文件名

     

    四、正则表达式元字符

        与grep一样,sed也支持特殊元字符,来进行模式查找、替换。不同的是,sed使用的正则表达式是括在斜杠线"/"之间的模式。

        如果要把正则表达式分隔符"/"改为另一个字符,比如o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符即可。

    例如:

    [plain] view plaincopy

    1. sed -n 'o^Myop' datafile  


    常用的正则表达式如下:

     元字符

     功能

     示例

     ^

     行首定位符

     /^my/ 匹配所有以my开头的行

     $

     行尾定位符

     /my$/ 匹配所有以my结尾的行

     .

     匹配除换行符以外的单个字符

     /m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行

     *

     匹配零个或多个前导字符

     /my*/ 匹配包含字母m,后跟零个或多个y字母的行

     []

     匹配指定字符组内的任一字符

     /[Mm]y/ 匹配包含My或my的行

     [^]

     匹配不在指定字符组内的任一字符

     /[^Mm]y/ 匹配包含y,但y之前的那个字符不是M或m的行

     ..

     保存已匹配的字符

     1,20s/youself/1r/ 标记元字符之间的模式,并将其保存为标签1,之后可以使用1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。

     &

     保存查找串以便在替换串中引用

     s/my/**&**/  符号&代表查找串。my将被替换为**my**

     <

     词首定位符

     /<my/ 匹配包含以my开头的单词的行

     >

     词尾定位符

     /my>/ 匹配包含以my结尾的单词的行

     x{m}

     连续m个x

     /9{5}/匹配包含连续5个9的行

     x{m,}

     至少m个x

     /9{5,}/ 匹配包含至少连续5个9的行

     x{m,n}

     至少m个,但不超过n个x

     /9{5,7}/ 匹配包含连续5到7个9的行

     

    五、sed的退出状态

        sed不向grep一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。

    六、常用范例

    1、p命令

        命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容。

    例子:

    [plain] view plaincopy

    1. (1)sed '/my/p' datafile  
    2. #默认情况下,sed把所有输入行都打印在标准输出上。如果某行匹配模式my,p命令将把该行另外打印一遍。  
    3. (2)sed -n '/my/p' datafile  
    4. #选项-n取消sed默认的打印,p命令把匹配模式my的行打印一遍。  

     

    2、d命令

        命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,然后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。如果发出的是命令d,当前模式空间里的输入行会被删除,不被显示。

    例子:

    [plain] view plaincopy

    1. (1)sed '$d' datafile  
    2. #删除最后一行,其余的都被显示  
    3. (2)sed '/my/d' datafile  
    4. #删除包含my的行,其余的都被显示  

     

    3、s命令

    例子:

    [plain] view plaincopy

    1. (1)sed 's/^My/You/g' datafile  
    2. #命令末端的g表示在行内进行全局替换,也就是说如果某行出现多个My,所有的My都被替换为You。  
    3. (2)sed -n '1,20s/My$/You/gp' datafile  
    4. #取消默认输出,处理1到20行里匹配以My结尾的行,把行内所有的My替换为You,并打印到屏幕上。  
    5. (3)sed 's#My#Your#g' datafile  
    6. #紧跟在s命令后的字符就是查找串和替换串之间的分隔符。分隔符默认为正斜杠,但可以改变。无论什么字符(换行符、反斜线除外),只要紧跟s命令,就成了新的串分隔符。  


     

    4、e选项

       -e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。

    例子:

    [plain] view plaincopy

    1. sed -e '1,10d' -e 's/My/Your/g' datafile  
    2. #选项-e用于进行多重编辑。第一重编辑删除第1-3行。第二重编辑将出现的所有My替换为Your。因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。  

     

    5、r命令

    r命令是读命令。sed使用该命令将一个文本文件中的内容加到当前文件的特定位置上。

    例如:

    [plain] view plaincopy

    1. sed '/My/r introduce.txt' datafile  
    2. #如果在文件datafile的某一行匹配到模式My,就在该行后读入文件introduce.txt的内容。如果出现My的行不止一行,则在出现My的各行后都读入introduce.txt文件的内容。  

     

    6、w命令

    例子:

    [plain] view plaincopy

    1. sed -n '/hrwang/w me.txt' datafile  

     

    7、a 命令

        a 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。

    例子:

    [plain] view plaincopy

    1. sed '/^hrwang/a  
    2. >hrwang and mjfan are husband  
    3. >and wife' datafile  
    4. #如果在datafile文件中发现匹配以hrwang开头的行,则在该行下面追加hrwang and mjfan are husband and wife  

     

    8、i 命令

    i 命令是在当前行的前面插入新的文本。

     

    9、c 命令

    sed使用该命令将已有文本修改成新的文本。

     

    10、n命令

    sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。

    例如:

    [plain] view plaincopy

    1. sed '/hrwang/{n;s/My/Your/;}' datafile  

    注:如果需要使用多条命令,或者需要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或这用分号分割同一行中的多条命令。

     

    11、y命令

        该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。例如,y/abc/ABC/将把所有小写的a转换成A,小写的b转换成B,小写的c转换成C。

    例如:

    [plain] view plaincopy

    1. sed '1,20y/hrwang12/HRWANG^$/' datafile  
    2. #将1到20行内,所有的小写hrwang转换成大写,将1转换成^,将2转换成$。  
    3. #正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。  

     

    12、q命令

        q命令将导致sed程序退出,不再进行其它的处理。

    [plain] view plaincopy

    1. sed '/hrwang/{s/hrwang/HRWANG/;q;}' datafile  

     

    13、h命令和g命令

    为了更好说明这两个命令,我们先创建如下的文本文件:

    [plain] view plaincopy

    1. #cat datafile  
    2. My name is hrwang.  
    3. Your name is mjfan.  
    4. hrwang is mjfan's husband.  
    5. mjfan is hrwang's wife.  

     

    [plain] view plaincopy

    1. sed -e '/hrwang/h' -e '$G' datafile  
    2. sed -e '/hrwang/H' -e '$G' datafile  
    3. #通过上面两条命令,你会发现h会把原来暂存缓冲区的内容清除,只保存最近一次执行h时保存进去的模式空间的内容。而H命令则把每次匹配hrwnag的行都追加保存在暂存缓冲区。  
    4. sed -e '/hrwang/H' -e '$g' datafile  
    5. sed -e '/hrwang/H' -e '$G' datafile  
    6. #通过上面两条命令,你会发现g把暂存缓冲区中的内容替换掉了模式空间中当前行的内容,此处即替换了最后一行。而G命令则把暂存缓冲区的内容追加到了模式空间的当前行后。此处即追加到了末尾。  

     

    补充知识点:sed特殊用法

    [plain] view plaincopy

    1. sed -n '/root/w a.txt'    #将匹配行输出到文件  
    2. sed '/root/r abc.txt' /etc/passwd #把abc.txt的文件内容读入到root匹配行后  
    3. sed -n '/root/w a.txt'  
    4. sed -n '/root/{=;p}' /etc/passwd #打印行号和匹配root的行  
    5. sed -n '/root/{n;d}' /etc/passwd #将匹配root行的下一行删除  
    6. sed -n '/root/{N;d}' /etc/passwd #将匹配root行和下一行都删除  
    7. sed '22{h;d};23,33{H;d};44G' pass  

    七、sed脚本编写方法

    1、从文件读入命令

    [plain] view plaincopy

    1. sed -f sed.sh  

    sed.sh文件内容:

    [plain] view plaincopy

    1. s/root/yerik/p  
    2. s/bash/csh/p  

     

    2、直接运行脚本 ./sed.sh /etc/passwd

    [plain] view plaincopy

    1. #!/bib/sed -f  
    2. s/root/yerik/p  
    3. s/bash/csh/p  

    八、小技巧

    1、用sed 输出自己的IP 地址

    [plain] view plaincopy

    1. ifconfig eth0 |sed '2p' |sed 's/^.*addr:/ /g' |sed 's/B.*$ / /g'  

     

    2、在sed的命令行中引用shell变量时要使用双引号,而不是通常所用的单引号。下面是一个根据name变量的内容来删除named.conf文件中zone段的脚本:

    name='zone "localhost"'

    [plain] view plaincopy

    1. sed "/$name/,/};/d" named.conf   

     

    3、保持和获取:h命令和G命令

    [plain] view plaincopy

    1. $ sed -e '/test/h' -e '$G example  

        在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

     

    4、保持和互换:h命令和x命令

    [plain] view plaincopy

    1. $ sed -e '/test/h' -e '/check/x' example   

       互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。

     

     

    九、练习

    1,删除文件每行的第一个字符。

    [plain] view plaincopy

    1. sed -n 's/^.//gp' /etc/passwd  
    2. sed -nr 's/(.)(.*)/2/p' /etc/passwd  

     

    2,删除文件每行的第二个字符。

    [plain] view plaincopy

    1. sed -nr 's/(.)(.)(.*)/13/p' /etc/passwd  

     

    3,删除文件每行的最后一个字符。

    [plain] view plaincopy

    1. sed -nr 's/.$//p' /etc/passwd  
    2. sed -nr 's/(.*)(.)/1/p' /etc/passwd  

     

    4,删除文件每行的倒数第二个字符。

    [plain] view plaincopy

    1. sed -nr 's/(.*)(.)(.)/13/p' /etc/passwd  

     

    5,删除文件每行的第二个单词。

    [plain] view plaincopy

    1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/1235/p' /etc/passwd  

     

    6,删除文件每行的倒数第二个单词。

    [plain] view plaincopy

    1. sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]*)/12456/p' /etc/samba/smb.conf  

     

    7,删除文件每行的最后一个单词。

    [plain] view plaincopy

    1. sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]*)/124/p' /etc/samba/smb.conf  

     

    8,交换每行的第一个字符和第二个字符。

    [plain] view plaincopy

    1. sed -nr 's/(.)(.)(.*)/213/p' /etc/passwd  

     

    9,交换每行的第一个单词和第二个单词。

    [plain] view plaincopy

    1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/14325/p' /etc/samba/smb.conf  

     

    10,交换每行的第一个单词和最后一个单词。

    [plain] view plaincopy

    1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/14325/p' /etc/passwd  

     

    11,删除一个文件中所有的数字。

    [plain] view plaincopy

    1. sed 's/[0-9]*//g' /etc/passwd  

     

    12,删除每行开头的所有空格。

    [plain] view plaincopy

    1. sed -n 's/^ *//p' /etc/samba/smb.conf   
    2. sed -nr 's/( *)(.*)/2/p' testp  

     

    13,用制表符替换文件中出现的所有空格。

    [plain] view plaincopy

    1. sed -n 's/ / /gp' pass  

     

    14,把所有大写字母用括号()括起来。

    [plain] view plaincopy

    1. sed -nr 's/([A-Z])/(&)/gp' testp   
    2. sed -n 's/[A-Z]/(&)/gp' testp  

    15,打印每行3次。

    [plain] view plaincopy

    1. sed 'p;p' pass  

     

    16,隔行删除。

    [plain] view plaincopy

    1. sed -n '1~2p' pass  

     

    17,把文件从第22行到第33行复制到第44行后面。

    [plain] view plaincopy

    1. sed '1,21h;22h;23,33H;44G' pass  

     

    18,把文件从第22行到第33行移动到第44行后面。

    [plain] view plaincopy

    1. sed '22{h;d};23,33{H;d};44G' pass  

     

    19,只显示每行的第一个单词。

    [plain] view plaincopy

    1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)(.*)/2/p' /etc/passwd  

     

    20,打印每行的第一个单词和第三个单词。

    [plain] view plaincopy

    1. sed -nr 's/([^a-Z]*)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/2--4/p' /etc/passwd  

     

    21,将格式为    mm/yy/dd    的日期格式换成   mm;yy;dd

    [plain] view plaincopy

    1. date +%m/%Y/%d |sed -n 's#/#;#gp'  

     

    22, 逆向输出

    [plain] view plaincopy

    1. cat a.txt  
    2. ABC  
    3. DEF  
    4. XYZ  
    5. 输出样式变成  
    6. XYZ  
    7. DEF  
    8. ABC  
  • 相关阅读:
    Servlet
    MySQL游标
    MySQL数据库的备份和还原
    MySQL安全管理
    MySQL存储过程
    MySQL联结——实现多表查询
    MySQL视图
    MySQL触发器
    asp.net core 读取连接字符串
    form表单提交前进行ajax验证
  • 原文地址:https://www.cnblogs.com/liujianzuo888/p/4975291.html
Copyright © 2011-2022 走看看