• SHELL脚本之正则表达式


      这部分内容可以说是学习shell脚本之前必学的内容。如果你这部分内容学的越好,那么你的shell脚本编写能力就会越强。所以不要嫌弃这部分内容啰嗦,也不要怕麻烦,要用心学习。一定要多加练习,练习多了就能熟练掌握了。

      在计算机科学中,正则表达式是这样解释的:它是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或者其他工具里,正则表达式通常被用来检索或者替换那些符合模式的文本内容。

      其实正则表达式,只是一种思想,一种表示方法。只要我们使用的工具支持表示这种思想那么这个工具就可以处理正则表达式的字符串。常用的工具有grep、sed和awk等。

    grep/egrep

      语法:grep [-cinvABC] 'word' filename

      -c:打印符合要求的行数;

      -i:忽略大小写;

      -n:在输出符合要求的行的同时连行号一起输出;

      -v:打印不符合要求的行;

      -A:后跟一个数字(有无空格都可以),例如-A2则表示打印符合要求的行以及下面的两行;

      -B:后跟一个数字,例如-B2则表示打印符合要求的行以及上面的两行;

      -C:后跟一个数字,例如-C2则表示打印符合要求的行以及上下各两行;

    [root@localhost test]# grep -A2 halt /etc/passwd
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost test]# grep -B2 halt /etc/passwd
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    [root@localhost test]# grep -C2 halt /etc/passwd
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost test]#
    

      1、过滤出带有某个关键词的行,并输出行号

    [root@localhost test]# grep -n 'root' /etc/passwd
    1:root:x:0:0:root:/root:/bin/bash
    10:operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost test]# 
    

      2、过滤不带某个关键词的行,并输出行号

    [root@localhost test]# grep -vn 'user_' /etc/passwd
    1:root:x:0:0:root:/root:/bin/bash
    2:bin:x:1:1:bin:/bin:/sbin/nologin
    3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4:adm:x:3:4:adm:/var/adm:/sbin/nologin
    5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6:sync:x:5:0:sync:/sbin:/bin/sync
    7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8:halt:x:7:0:halt:/sbin:/sbin/halt
    9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10:operator:x:11:0:operator:/root:/sbin/nologin
    11:games:x:12:100:games:/usr/games:/sbin/nologin
    12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    13:nobody:x:99:99:Nobody:/:/sbin/nologin
    14:systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    15:dbus:x:81:81:System message bus:/:/sbin/nologin
    16:polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    17:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    18:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    19:mysql:x:1000:1000::/home/mysql:/bin/bash
    20:www:x:1001:1001::/home/www:/bin/bash
    21:zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
    22:test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
    

      3、过滤出所有包含数字的行

    [root@localhost ~]# echo aaaaaaaaaaaaaaaa > test.txt
    [root@localhost ~]# echo 1212222aaaaaaaaaaaa >> test.txt
    [root@localhost ~]# echo 2334242423423472934792 >> test.txt
    [root@localhost ~]# echo bbbbbbbbbbbbnbbb >> test.txt
    [root@localhost ~]# echo 43345345fdfgdfgdfg >> test.txt
    [root@localhost ~]# cat test.txt 
    aaaaaaaaaaaaaaaa
    1212222aaaaaaaaaaaa
    2334242423423472934792
    bbbbbbbbbbbbnbbb
    43345345fdfgdfgdfg
    [root@localhost ~]# grep [0-9] test.txt 
    1212222aaaaaaaaaaaa
    2334242423423472934792
    43345345fdfgdfgdfg
    [root@localhost ~]#
    

      这里提到了“[]”的应用,如果是数字的话就用[0-9]这样的形式,当然有时候也可以用这样的形式[15]即只包含1或者5,注意,它不会认为是15。如果要过滤出数字以及大小写字母则要这样[0-9a-zA-Z]。另外[]还有一种形式,就是[^字符]表示除[]内的字符之外的字符。

    [root@localhost ~]# grep '[^r]oo' /etc/passwd
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    [root@localhost ~]#
    

      这就表示筛选包含oo字符串,但是不包含r的字符。

      4、过滤出文档中以某个字符开头或者某个字符结尾的行

    [root@localhost ~]# grep '^r' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    [root@localhost ~]# grep 'n$' /etc/passwd
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    

      在正则表达式中,“^”表示行的开始,“$”表示行的结尾,那么空行则表示“^$”,如果你只想筛选出非空行,则可以使用“grep -v '^$' filename”得到你想要的结果。

    [root@localhost ~]# echo 12344 > test.txt 
    [root@localhost ~]# echo sdfsadffa >> test.txt 
    [root@localhost ~]# echo '' >> test.txt 
    [root@localhost ~]# echo 'ssss32323' >> test.txt 
    [root@localhost ~]# cat test.txt 
    12344
    sdfsadffa
    
    ssss32323
    [root@localhost ~]# grep '^$' test.txt 
    
    [root@localhost ~]# grep -C2 '^$' test.txt 
    12344
    sdfsadffa
    
    ssss32323
    [root@localhost ~]# grep '^[a-zA-Z]' test.txt 
    sdfsadffa
    ssss32323
    [root@localhost ~]#
    

      5、过滤任意一个字符与重复字符

    [root@localhost ~]# grep 'r..t' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    [root@localhost ~]# 
    

      “.”表示任意一个字符,上例中,就是把符合r与o之间有两个任意字符的行过滤出来。

      “*”表示零个或多个前面的字符。

    [root@localhost ~]# grep 'ooo*' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    [root@localhost ~]# 
    [root@localhost ~]# grep '.*' /etc/passwd | wc -l
    123
    [root@localhost ~]#
    

      “.*”表示另个或者或者多个任意字符,空行也包含在内。

      6、指定要过滤字符出现的次数

    [root@localhost ~]# grep 'o{2}' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    [root@localhost ~]# 
    

      这里用到了“{}”,其内部为数字,表示前面的数字要重复的次数。上例中表示包含有两个o即‘oo’的行。注意,“{}”左右都要加上转义字符“”。另外,使用“{}”我们还可以表示一个范围的,具体格式是“{n1,n2}”,其中n1<n2,表示重复n1到n2次数前面的字符,n2还可以为空,则表示大于等于n1次。

      上面部分讲的grep,另外笔者常常用到egrep这个工具,简单点讲,后者是前者的扩展版本,我们可以用egrep完成grep不能完成的工作,当然了grep能完成的egrep完全可以完成。如果你嫌麻烦,egrep了解一下即可。因为grep的功能已经足够可以胜任你的日常工作了。

    [root@localhost ~]# cat test.txt 
    rot:x:0:0:/rot:/bin/bash
    
    operator:x:11:0:operator:/root:/sbin/nologin
    
    operator:x:11:0:operator:/rooot:/sbin/nologin
    
    roooot:x:0:0:/rooooot:/bin/bash
    
    1111111111111111111111111111111
    
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      1、筛选一个或一个以上前面的字符

    [root@localhost ~]# egrep 'o+' test.txt 
    rot:x:0:0:/rot:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# egrep 'o+' test.txt 
    rot:x:0:0:/rot:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# egrep 'oo+' test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# egrep 'ooo+' test.txt 
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]#

      2、筛选零个或者一个前面的字符

    [root@localhost ~]# egrep 'o?' test.txt 
    rot:x:0:0:/rot:/bin/bash
    
    operator:x:11:0:operator:/root:/sbin/nologin
    
    operator:x:11:0:operator:/rooot:/sbin/nologin
    
    roooot:x:0:0:/rooooot:/bin/bash
    
    1111111111111111111111111111111
    
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# egrep 'oo?' test.txt 
    rot:x:0:0:/rot:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# egrep 'ooo?' test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# 
    

      3、筛选字符串1或者字符串2

    [root@localhost ~]# egrep '111|aaa' test.txt 
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      4、egrep中的“()”的应用

    [root@localhost ~]# egrep 'r(oo)|(at)o' test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# 
    

      用“()”表示一个整体,例如(oo)+就表示1个oo或者多个oo。

    [root@localhost ~]# egrep '(oo)+' test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# 
    

    sed工具的使用

       grep工具的功能其实还不够强大,其实说白看,grep实现的只是查找功能,而他却不能实现把查找的内容替换掉。sed工具以及下面要讲的awk工具就能实现把替换的文本输出到屏幕上的功能了,而且还有其他更丰富的功能。sed和awk都是流式编辑器,是针对文档的行来操作的。

      1、打印某行sed -n 'n'p filename单引号内的n是一个数字,表示第几行

    [root@localhost ~]# cat test.txt 
    rot:x:0:0:/rot:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# sed -n '2'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# 
    

      2、打印多行,打印整个文档用 -n '1,$'p

    [root@localhost ~]# sed -n '2,4'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]# sed -n '1,$'p test.txt 
    rot:x:0:0:/rot:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      3、打印包含某个字符的行

    [root@localhost ~]# sed -n '/root/'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# 
    

      上面grep中使用的特殊字符,如“^”、“$”,“.”、“*”等,同样也能在sed中使用。

    [root@localhost ~]# sed -n '/^1/'p test.txt 
    1111111111111111111111111111111
    [root@localhost ~]# sed -n '/in$/'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    [root@localhost ~]# sed -n '/r..t/'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# sed -n '/ooo*/'p test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    [root@localhost ~]#
    

      4、-e可以实现多个行为

    [root@localhost ~]# sed -e '1'p  -e '/111/'p -n test.txt 
    rot:x:0:0:/rot:/bin/bash
    1111111111111111111111111111111
    [root@localhost ~]# 
    

      5、删除某行或者多行

    [root@localhost ~]# sed '1'd test.txt 
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# sed '1,3'd test.txt 
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# sed '/oot/'d test.txt 
    rot:x:0:0:/rot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      “d”这个字符就是删除的动作了,不仅可以删除指定的单行以及多行,而且还可以删除匹配某个字符的行,另外还可以删除从某一行到文档末尾。

    [root@localhost ~]# sed '2,$'d test.txt 
    rot:x:0:0:/rot:/bin/bash
    [root@localhost ~]# 
    

      6、替换字符或字符串

    [root@localhost ~]# sed '1,2s/ot/to/g' test.txt 
    rto:x:0:0:/rto:/bin/bash
    operator:x:11:0:operator:/roto:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      上例中的“s”就是替换的命令,“g”为本行中全局替换,如果不加“g”,只换该行中出现的第一次。

      除了可以使用“/”外,还可以使用其他特殊字符,例如“#”或者“@”都没有问题。

    [root@localhost ~]# sed '1,2s#ot#to#g' test.txt 
    rto:x:0:0:/rto:/bin/bash
    operator:x:11:0:operator:/roto:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# sed '1,2s@ot@to@g' test.txt 
    rto:x:0:0:/rto:/bin/bash
    operator:x:11:0:operator:/roto:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      现在思考一下,如何删除文档中的所有数字或者字母?

    [root@localhost ~]# sed '1,$s/[0-9]//g' test.txt 
    rot:x:::/rot:/bin/bash
    operator:x:::operator:/root:/sbin/nologin
    operator:x:::operator:/rooot:/sbin/nologin
    roooot:x:::/rooooot:/bin/bash
    
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# sed 's/[0-9]//g' test.txt 
    rot:x:::/rot:/bin/bash
    operator:x:::operator:/root:/sbin/nologin
    operator:x:::operator:/rooot:/sbin/nologin
    roooot:x:::/rooooot:/bin/bash
    
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    [root@localhost ~]# sed 's/[a-zA-Z]//g' test.txt 
    ::0:0:/://
    ::11:0::/://
    ::11:0::/://
    ::0:0:/://
    1111111111111111111111111111111
    
    [root@localhost ~]# sed 's/[0-9a-zA-Z]//g' test.txt 
    ::::/://
    :::::/://
    :::::/://
    ::::/://
    
    
    [root@localhost ~]# 
    

      7、调换两个字符串的位置

    [root@localhost ~]# sed 's/(rot)(.*)(bash)/321/' test.txt
    bash:x:0:0:/rot:/bin/rot
    operator:x:11:0:operator:/root:/sbin/nologin
    operator:x:11:0:operator:/rooot:/sbin/nologin
    roooot:x:0:0:/rooooot:/bin/bash
    1111111111111111111111111111111
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    

      这就需要解释一下了,上例中用“()”把所想要替换的字符括起来成为一个整体,因为括号在sed中属于特殊字符,所以需要在前面加上转义字符“”,替换时则写成“1”,“2”,“3”的形式。

       在某一行前或者后增加指定内容。

    [root@localhost ~]# sed 's/^.*$/123&/' test.txt 
    123rot:x:0:0:/rot:/bin/bash
    123operator:x:11:0:operator:/root:/sbin/nologin
    123operator:x:11:0:operator:/rooot:/sbin/nologin
    123roooot:x:0:0:/rooooot:/bin/bash
    1231111111111111111111111111111111
    123aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    [root@localhost ~]# 
    [root@localhost ~]# sed 's/^.*/&123/' test.txt 
    rot:x:0:0:/rot:/bin/bash123
    operator:x:11:0:operator:/root:/sbin/nologin123
    operator:x:11:0:operator:/rooot:/sbin/nologin123
    roooot:x:0:0:/rooooot:/bin/bash123
    1111111111111111111111111111111123
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa123
    [root@localhost ~]# 
    

      8、直接修改文件内容

      sed -i 's/:/#/g' test.txt,这样就可以直接更改test.txt文件的内容了。由于这个命令可以直接把文件修改,所以在修改前最好先复制一下文件以免改错。

    sed练习

      1、把/etc/passwd复制到/root/test.txt,用sed打印所有行;

    [root@localhost ~]# cp /etc/passwd /root/test.txt;sed -n '1,$'p test.txt

      2、打印test.txt的3到10行;

    [root@localhost ~]# sed -n '3,10'p test.txt

      3、打印test.txt中包含‘root’的行;

    [root@localhost ~]# sed -n '/root/'p test.txt

      4、删除test.txt的15行以及后边所有行;

    [root@localhost ~]# sed '15,$'d test.txt

      5、删除test.txt中包含‘bash’的行;

    [root@localhost ~]# sed '/bash/'d test.txt

      6、替换test.txt中的‘root’为‘toor’;

    [root@localhost ~]# sed 's/root/toor/g' test.txt

      7、替换test.txt中的‘/sbin/nologin’为‘/bin/login’;

    [root@localhost ~]# sed 's//sbin/nologin//bin/login/g' test.txt 
    [root@localhost ~]# sed 's#/sbin/nologin#/bin/login#g' test.txt

      8、删除test.txt中5到10行中的所有数字;

    [root@localhost ~]# sed '5,10s/[0-9]//g' test.txt

      9、删除test.txt中所有特殊字符(除了数字以及大小写字母);

    [root@localhost ~]# sed 's/[^0-9a-zA-Z]//g' test.txt 

      10、把test.txt中第一个单词和最后一个单词调换位置;

    [root@localhost ~]# sed 's/(^[a-zA-Z][a-zA-Z]*)([^a-zA-Z].*)([^a-zA-Z])([a-zA-Z][a-zA-Z]*$)/4231/' test.txt

      11、把test.txt中出现的第一个数字和最后一个单词替换位置;

    [root@localhost ~]# sed 's#([^0-9][^0-9]*)([0-9][0-9]*)([^0-9].*)([^a-zA-Z])([a-zA-Z][a-zA-Z]*$)#15342#' test.txt

      12、把test.txt中第一个数字移动到行的末尾;

    [root@localhost ~]# sed 's#([^0-9][^0-9]*)([0-9][0-9]*)([^0-9].*$)#132#' test.txt

      13、在test.txt20行到末尾行最前面加‘aaa’;

    [root@localhost ~]# sed '20,$s/^.*$/aaa:&/' test.txt
    

    awk工具使用

      上面也提到了awk和sed一样是流式编辑器,也是针对文档中的行来操作的,一行一行的去指向。awk比sed更加强大,他能做到sed能做到的,同样也能做到sed不能做到的。awk工具其实是很复杂的,有专门的书籍来介绍它的应用。

      1、截取文档中的某个段 

    [root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $1}'
    root
    bin
    [root@localhost ~]# 
    

      解释一下,-F选项的作用是指定分隔符,如果不加-F指定,则以空格或者tab为分隔符。

    [root@localhost ~]# head -n2 /etc/inittab 
    # inittab is no longer used when using systemd.
    #
    [root@localhost ~]# head -n2 /etc/inittab | awk '{print $2,$3}'
    inittab is
     
    [root@localhost ~]# 
    

      print为打印动作,用来打印某个字段。$1为第一个字段,$2为第二个字段,以此类推,有一个特殊的那就是$0,它代表整行。

    [root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $0}'
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    [root@localhost ~]# 
    

      注意awk的格式,-F后紧跟单引号,然后里面为分隔符,print的动作要用‘{}’括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双括号括起来。

    [root@localhost ~]# head -n2 test.txt | awk -F ':' '{print $1"@"$2"@"$3}'
    root@x@0
    bin@x@1
    [root@localhost ~]# 
    

      2、匹配字符或字符串

    [root@localhost ~]# awk '/root/' test.txt 
    root:x:0:0:root:/root:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# 
    

      跟sed很类似吧,不过还有比sed更强大的匹配

    [root@localhost ~]# awk -F ':' '$1~/root/' test.txt 
    root:x:0:0:root:/root:/bin/bash
    [root@localhost ~]# 
    

      可以让某个段去匹配,这里的‘~’就是匹配的意思。

    [root@localhost ~]# awk -F ':' '/root/ {print $3} /test/ {print $3}' test.txt 
    0
    11
    1003
    [root@localhost ~]# 
    

      awk还可以多次匹配,如上例中匹配完root,再匹配test,还可以只打印所匹配的字段。

    [root@localhost ~]# awk -F ':' '$1~/root/ {print $1}' test.txt 
    root
    [root@localhost ~]#
    

      3、条件操作符

    [root@localhost ~]# awk -F ':' '$3=="0"' test.txt 
    root:x:0:0:root:/root:/bin/bash
    [root@localhost ~]# 
    

      awk中是可以逻辑符号判断的,比如‘==’就是等于,也可以理解为“精确匹配”。另外也有“>”、“>=”、“<”、“<=”、“!=”等等,值得注意的是,即使$3为数字,awk也不会把它当做是一个数字。所以不要妄图拿$3当做数字和数字做比较。

    [root@localhost ~]# cat test.txt | awk -F ':' '$3>="500"'
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    [root@localhost ~]#
    

      这样是得不到我们想要对的效果的。这里只是字符与字符之间的比较,‘6’是>‘500’的。

    [root@localhost ~]# cat test.txt | awk -F ':' '$7!="/sbin/nologin"'
    root:x:0:0:root:/root:/bin/bash
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mysql:x:1000:1000::/home/mysql:/bin/bash
    www:x:1001:1001::/home/www:/bin/bash
    zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
    test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
    

      上例中用的是‘!=’即不匹配。

    [root@localhost ~]# awk -F ':' '$3<$4' test.txt 
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    [root@localhost ~]# 
    

      另外还可以使用‘&&’和‘||’表示“并且”和“或者”的意思。

    [root@localhost ~]# awk -F ':' '$3>"5" && $3<"7"' test.txt 
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    [root@localhost ~]#
    [root@localhost ~]# awk -F ':' '$3<"1" || $3 >"8"' test.txt 
    root:x:0:0:root:/root:/bin/bash
    nobody:x:99:99:Nobody:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    [root@localhost ~]# 
    

      4、awk的内置变量

      NF:用分隔符分割后一共多少段;

      NR:行数

    [root@localhost ~]# head -n5 test.txt | awk -F ':' '{print NF}'
    7
    7
    7
    7
    7
    [root@localhost ~]# head -n5 test.txt | awk -F ':' '{print $NF}'
    /bin/bash
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    [root@localhost ~]#
    

      上例中,打印总共的段数以及最后一段的值。

    [root@localhost ~]# awk 'NR>=20' test.txt 
    www:x:1001:1001::/home/www:/bin/bash
    zhouguowei:x:1002:1002::/home/zhouguowei:/bin/bash
    test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
    user_00:x:1004:100::/home/user_00:/bin/bash
    user_01:x:1005:100::/home/user_01:/bin/bash
    user_02:x:1006:100::/home/user_02:/bin/bash
    user_03:x:1007:100::/home/user_03:/bin/bash
    user_04:x:1008:100::/home/user_04:/bin/bash
    user_05:x:1009:100::/home/user_05:/bin/bash
    user_06:x:1010:100::/home/user_06:/bin/bash
    user_07:x:1011:100::/home/user_07:/bin/bash
    user_08:x:1012:100::/home/user_08:/bin/bash
    user_09:x:1013:100::/home/user_09:/bin/bash
    user_10:x:1014:100::/home/user_10:/bin/bash
    user_11:x:1015:100::/home/user_11:/bin/bash
    

      可以使用NR作为条件,来打印指定的行。

    [root@localhost ~]# awk -F ':' 'NR>=20 && $1~/test/' test.txt 
    test:x:1003:1003:test,test'office,123456789,123654789:/home/test:/bin/bash
    [root@localhost ~]#
    

      5、awk中的数学运算

    [root@localhost ~]# head -n5 test.txt | awk -F ':' '$1="root"'
    root x 0 0 root /root /bin/bash
    root x 1 1 bin /bin /sbin/nologin
    root x 2 2 daemon /sbin /sbin/nologin
    root x 3 4 adm /var/adm /sbin/nologin
    root x 4 7 lp /var/spool/lpd /sbin/nologin
    [root@localhost ~]#
    [root@localhost ~]# head -n2 test.txt | awk -F ':' '{$7=$3+$4;print $3,$4,$7}'
    0 0 0
    1 1 2
    [root@localhost ~]# 
    

      当然还可以计算某个段的总和。

    [root@localhost ~]# cat test.txt | awk -F ':' '{(tot+=$3)};END {print tot}'
    112067
    [root@localhost ~]# 
    

      这里的END做注意一下,表示所有的行都已经执行,这是awk特有的语法,其实awk连同sed都可以写成一个脚本文件,而且有它们特有的语法,在awk中使用if判断、for循环都是可以的。

    [root@localhost ~]# awk -F ':' '{if ($1=="root") print $0}' test.txt 
    root:x:0:0:root:/root:/bin/bash
    [root@localhost ~]# 
    

    awk练习

      1、用awk打印整个test.txt;

    [root@localhost ~]# awk '{print $0}' test.txt

      2、查找所有包含‘bash’的行;

    [root@localhost ~]# awk '/bash/' test.txt

      3、用‘:’作为分隔符,查找第三段等于0的行;

    [root@localhost ~]# awk -F ':' '$3==0' test.txt

      4、用‘:’作为分隔符,查找第一段为root的行,并把该段的root换成toor;

    [root@localhost ~]# awk -F':' '$1=="root"' test.txt |sed 's/root/toor/'

      5、用‘:’作为分隔符,打印最后一段;

    [root@localhost ~]# awk -F ':' '{print $NF}' test.txt 

      6、打印行数大于20的所有行;

    [root@localhost ~]# awk 'NR>20' test.txt

      7、用‘:’作为分隔符,打印所有第三段小于第四段的行;

    [root@localhost ~]# awk -F ':' '$3<$4' test.txt

      8、用‘:’作为分隔符,打印第一段以及最后一段,并且中间中‘@’连接;

    [root@localhost ~]# awk -F ':' '{print $1"@"$NF}' test.txt 

      9、用‘:’作为分隔符,把整个文档的第四段相加,求和;

    [root@localhost ~]# awk -F ':' '{(tot+=$4)};END {print tot}' test.txt
    

      

      

  • 相关阅读:
    Winform自定义窗体样式,实现标题栏可灵活自定义
    肿瘤转录组数分析CRN:Cancer RNA-Seq Nexus
    TCGA系列--miRNA数据分析
    TCGA系列--甲基化神器mexpress
    R:reshape2包中的melt
    TCGA系列--GDCRNATools
    R软件中排序:sort(),rank(),order()
    TCGA系列--TCGA长链非编码RNA的可视化工具TANRIC
    记一次RabbitMQ解决分布式事务问题
    RabbitMQ整合Spring Booot【死信队列】
  • 原文地址:https://www.cnblogs.com/zhouguowei/p/9516043.html
Copyright © 2020-2023  润新知