• Shell脚本 --- 正则表达式和文本处理工具


    一 什么是正则

      正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。

    生活中处处都是正则:

        比如我们描述:4条腿

          你可能会想到的是四条腿的动物或者桌子,椅子等

        继续描述:4条腿,活的

              就只剩下四条腿的动物这一类了

    在linux中,通配符是由shell解释的,而正则表达式则是由命令解释的,下面我们就为大家介绍三种文本处理工具/命令:grep、sed、awk,它们三者均可以解释正则。

    二 grep

    参数

    -n  :显示行号 -o  :只显示匹配的内容 -q  :静默模式,没有任何输出,得用$?来判断执行成功没有,即有没有过滤到想要的内容

    -l  :如果匹配成功,则只将文件名打印出来,失败则不打印,通常-rl一起用,grep -rl 'root' /etc  -A  :如果匹配成功,则将匹配行及其后n行一起打印出来 -B  :如果匹配成功,则将匹配行及其前n行一起打印出来 -C  :如果匹配成功,则将匹配行及其前后n行一起打印出来 --color -c  :如果匹配成功,则将匹配到的行数打印出来 -E  :等于egrep,扩展 -i  :忽略大小写

    -v  :取反,不匹配 -w:匹配单词

    复制代码
    [root@MiWiFi-R3-srv ~]# cat a.txt 
    root123
    ROot asdf
    Root_123
    rOOtss
    root 123
    [root@MiWiFi-R3-srv ~]# grep -i "root" a.txt 
    root123
    ROot asdf
    Root_123
    rOOtss
    root 123
    [root@MiWiFi-R3-srv ~]# grep -w "root" a.txt 
    root 123
    复制代码

    grep种类 grep fgrep pgrep egrep

    正则介绍

    ^ 行首 $ 行尾 . 除了换行符以外的任意单个字符 * 前导字符的零个或多个 .* 所有字符 [] 字符组内的任一字符 [^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)   ^[^] 非字符组内的字符开头的行 [a-z] 小写字母 [A-Z] 大写字母 [a-Z] 小写和大写字母 [0-9] 数字 < 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词 > 单词尾

    扩展正则 sed  加 -r 参数 或转义 grep 加 -E 或 egrep 或转义 AWK  直接支持 但不包含{n,m} 可以使用--posix支持 [root@MiWiFi-R3-srv ~]#  awk '/ro{1,3}/{print}' /etc/passwd [root@MiWiFi-R3-srv ~]#  awk --posix '/ro{1,3}/{print}' /etc/passwd
      sed -n '/roo?/p' /etc/passwd    sed -rn '/roo?/p' /etc/passwd   ? 前导字符零个或一个 + 前导字符一个或多个 abc|def abc或def   a(bc|de)f abcf 或 adef   x{m}   x出现m次 x{m,}  x出现m次至多次(至少m次) x{m,n} x出现m次至n次
    posix定义的字符分类

    [:alnum:]  Alphanumeric characters. 匹配范围为 [a-zA-Z0-9]        [:alpha:]  Alphabetic characters. 匹配范围为 [a-zA-Z]        [:blank:]  Space or tab characters. 匹配范围为 空格和TAB键 [:cntrl:]  Control characters. 匹配控制键 例如 ^M  要按 ctrl+v 再按回车 才能输出 [:digit:]  Numeric characters. 匹配所有数字 [0-9]        [:graph:]  Characters  that  are  both printable and visible.  (A space is print-                   able, but not visible, while an a is both.) 匹配所有可见字符 但不包含空格和TAB 就是你在文本文档中按键盘上能用眼睛观察到的所有符号 [:lower:]  Lower-case alphabetic characters. 小写 [a-z]        [:print:]  Printable characters (characters that are not control characters.) 匹配所有可见字符 包括空格和TAB 能打印到纸上的所有符号 [:punct:]  Punctuation characters (characters that are not letter,  digits,  con- trol characters, or space characters). 特殊输入符号  +-=)(*&^%$#@!~`|"'{}[]:;?/>.<, 注意它不包含空格和TAB 这个集合不等于^[a-zA-Z0-9]        [:space:]  Space characters (such as space, tab, and formfeed, to name a few).

           [:upper:]  Upper-case alphabetic characters. 大写 [A-Z]        [:xdigit:] Characters that are hexadecimal digits. 16进制数 [0-f]

    使用方法: [root@seker ~]# grep --color '[[:alnum:]]' /etc/passwd

    复制代码
    正则表达式及字符处理
    目标文件/etc/passwd,使用grep命令或egrep
    1.显示出所有含有root的行:
    2.输出任何包含bash的所有行,还要输出紧接着这行的上下各两行的内容:
    3.  显示出有多少行含有nologin。
    4.显示出那些行含有root,并将行号一块输出。
    5.显示出文件中
    6.新建用户
        abominable
        abominate
        anomie
        atomize
        编写正则表达式,将他们匹配出来
        egrep 'a.omi(nabl|nat|z|)e' /etc/passwd
    7.建四个用户
        Alex213sb
        Wpq2222b
        yH438PIG
        egon666
        egon
    
        过滤出用户名组成是字母+数字+字母的行
    [root@MiWiFi-R3-srv ~]# egrep '^[a-Z]+[0-9]+[a-Z]+' /etc/passwd
    8.显示出/etc目录下所有包含root的文件名
    9. 过滤掉/etc/ssh/sshd_config内所有注释和所有空行
    grep -v '^#' /etc/ssh/sshd_config |grep -v '^ *$'
    复制代码

    三 sed

    sed 流编辑器 stream editer,是以行为单位的处理程序

    sed 流编辑器 stream editer

    语法 sed [options] 'command' in_file[s] options 部分 -n -e -i -f command 部分 '[地址1,地址2] [函数] [参数(标记)]'
    定址的方法 1.数字 2.正则 数字    十进制数 1 单行   1,3 范围 从第一行到第三行 2,+4 匹配行后若干行 4,~3   从第四行到下一个3的倍数行 2~3 第二行起每间隔三行的行 $ 尾行 1! 除了第一行以外的行 正则    正则必须用//包裹起来    扩展正则需要用 -r 参数或转义

    数字定址:sed -n '1p' /etc/passwd

    正则定址:sed -n '/^root/p' /etc/passwd
    正则介绍

    ^ 行首 $ 行尾 . 除了换行符以外的任意单个字符 * 前导字符的零个或多个 .* 所有字符 [] 字符组内的任一字符 [^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)   ^[^] 非字符组内的字符开头的行 [a-z] 小写字母 [A-Z] 大写字母 [a-Z] 小写和大写字母 [0-9] 数字 < 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词 > 单词尾

    扩展正则 加 -r 参数 或转义 sed -n '/roo?/p' /etc/passwd    sed -rn '/roo?/p' /etc/passwd   ? 前导字符零个或一个 + 前导字符一个或多个 abc|def abc或def   a(bc|de)f abcf 或 adef   x{m}   x出现m次 x{m,}  x出现m次至多次(至少m次) x{m,n} x出现m次至n次

    函数 增删改 a 后插 c 替换 i 前插 d 删除 输入输出 p 打印匹配的行 一般和 -n 参数连用,以屏蔽默认输出 r 从文件中读入 w 写入到文件中 控制流 !  命令取反 例: 1!d 删除第一行以外的行 {} 命令组合 命令用分号分隔 {1h;G} 可以理解为 -e 参数的另一种写法

    =  打印行号(输入行的号码,而非处理的次数行号) 例如: sed -n '2{=;p}' infile   n  读入下一行到模式空间 例:'4{n;d}' 删除第5行 N  而是追加下一行到模式空间,再把当前行和下一行同时应用后面的命令

    替换 s 字符串替换 s/old/new/
    $ sed -n 's/root/ABCDEF/p' /etc/passwd
    ABCDEF:x:0:0:root:/root:/bin/bash

    operator:x:11:0:operator:/ABCDEF:/sbin/nologin

    $ sed -n 's/root/ABCDEF/gp' /etc/passwd
    ABCDEF:x:0:0:ABCDEF:/ABCDEF:/bin/bash

    operator:x:11:0:operator:/ABCDEF:/sbin/nologin

    $ sed -n 's/root/ABCDEF/2p' /etc/passwd

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

    $ sed -n 's/root/ABCDEF/3p' /etc/passwd

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

    $ sed -n 's/root/ABCDEF/gp' /etc/passwd

    ABCDEF:x:0:0:ABCDEF:/ABCDEF:/bin/bash

    operator:x:11:0:operator:/ABCDEF:/sbin/nologin
    $

    () 保存被匹配的字符 以备反向引用N时使用 最多9个标签 标签顺序从左至右 & 替换时使用,在不定义标签时使用(反向引用)

    试做:
    删除第一个单词

    删除最后一个单词

    将第一个单词和最后一个单词兑换位置

    y 字符替换(变形)

    工作模式 模式空间和保持空间介绍

    $ sed  '1{p;p}' a.txt

    11111111

    11111111

    11111111

    22222222

    33333333

    44444444

    55555555

    66666666

    $

    置换 模式空间和保持空间(暂存空间) h 把模式空间内容覆盖到保持空间中 H 把模式空间内容追加到保持空间中 g 把保持空间内容覆盖到模式空间中 G 把保持空间内容追加到模式空间中 x 交换模式空间与保持空间的内容

    # cat test.sh 1111111 2222222 3333333 4444444 # sed  '{1h;2,3H;4G}'  ./test.sh 1111111 2222222 3333333 4444444 1111111 2222222 3333333 # sed  '{1h;2x;3g;$G}'  ./test.sh 1111111 1111111 2222222 4444444 2222222 #

    试做题

    将第一行插入到每个偶数行的后面

    $ sed  '1h;0~2G' a.txt

    11111111

    22222222

    11111111

    33333333

    44444444

    11111111

    55555555

    66666666

    11111111

    $

    颠倒输出

    $ sed '1!G;h;$!d' rev.txt

    xyz

    def

    abc

    $

    脚本方法 -f 参数 引用脚本(脚本的末尾不能有空格制表符或其他文本) # cat sed.sh 2,4d s/777/seker/ s/999/seker&seker/ # sed -f sed.sh test.txt 1111111 5555555 6666666 seker7777 8888888 seker999seker9999 #

    在脚本中指明解释器为sed # cat sed.sh #!/bin/sed -f 2,4d s/777/seker/ s/999/seker&seker/ # ./sed.sh test.txt 1111111 5555555 6666666 seker7777 8888888 seker999seker9999 #

    高级流控命令 b分支 t测试 分支命令用于无条件转移,测试命令用于有条件转移

    分支 branch 跳转的位置与标签相关联 如果有标签则跳转到标签所在的后面行继续执行 如果没有标签则跳转到脚本的结尾处. 标签 以冒号开始后接标签名 不要在标签名前后使用空格 跳转到标签指定位置 [root@stu254 ~]# grep seker /etc/passwd seker:x:500:500::/home/seker:/bin/bash [root@stu254 ~]# [root@stu254 ~]# grep seker /etc/passwd |sed ':top;s/seker/blues/;/seker/b top;s/5/555/' blues:x:55500:500::/home/blues:/bin/bash [root@stu254 ~]#

    命令分析:让单次替换(cmd1)循环执行,直到条件不满足 :top; 定义一个top标签 s/seker/blues/; cmd1 /seker/b top; 如果模式匹配则跳转到top标签 s/5/555/ 当上一条模式不匹配时,既会继续执行这一条

    选择执行 [root@stu254 ~]#  grep 'seker' /etc/passwd |sed 's/seker/blues/;/seker/b end;s/5/555/;:end;s/5/666/' blues:x:66600:500::/home/seker:/bin/bash [root@stu254 ~]#

    zorro:x:501:501::/home/zorro:/bin/bash [root@stu254 ~]#  grep 'zorro' /etc/passwd |sed 's/seker/blues/;/seker/b end;s/5/555/;:end;s/5/666/' zorro:x:6665501:501::/home/zorro:/bin/bash [root@stu254 ~]#

    命令分析: 执行cmd1,再去模式匹配,成功则跳转到cmd3开始执行,否则(模式不匹配)会按命令顺序逐个执行 s/seker/blues/; cmd1 /seker/b end; s/5/555/; cmd2 :end; s/5/666/ cmd3

    另一种选择执行 [root@stu254 ~]#  grep 'seker' /etc/passwd |sed 's/seker/blues/;/seker/b end;s/5/555/;b;:end;s/5/666/' blues:x:66600:500::/home/seker:/bin/bash

    [root@stu254 ~]#  grep 'zorro' /etc/passwd |sed 's/seker/blues/;/seker/b end;s/5/555/;b;:end;s/5/666/' zorro:x:55501:501::/home/zorro:/bin/bash [root@stu254 ~]#

    命令分析: 执行cmd1;模式匹配cmd2成功则执行cmd3;否则执行cmd2,再跳转到脚本末尾 s/seker/blues/; cmd1 /seker/b end; s/5/555/;  cmd2 b; :end; s/5/666/ cmd3

    测试命令,如果前一个替换命令执行成功则跳转到脚本末尾 (case结构) [root@stu254 ~]#  grep 'seker' /etc/passwd |sed 's/seker/ABC/;t;s/home/DEF/;t;s/bash/XYZ/' ABC:x:500:500::/home/seker:/bin/bash

    [root@stu254 ~]#  grep 'zorro' /etc/passwd |sed 's/seker/ABC/;t;s/home/DEF/;t;s/bash/XYZ/' zorro:x:501:501::/DEF/zorro:/bin/bash [root@stu254 ~]#

    与标签关联,跳转到标签位置 [root@stu254 ~]#  grep 'seker' /etc/passwd |sed 's/seker/ABC/;t end;s/home/DEF/;t;:end;s/bash/XYZ/' ABC:x:500:500::/home/seker:/bin/XYZ [root@stu254 ~]#

    [seker@seker ~]$ grep 'zorro' /etc/passwd |sed 's/seker/ABC/;t end;s/home/DEF/;t;:end;s/bash/XYZ/' zorro:x:501:501::/DEF/zorro:/bin/bash

    复制代码
    Sed作业:以/etc/passwd文件为模板
    
    1,删除文件每行的第一个字符。
    
    2,删除文件每行的第二个字符。
    
    3,删除文件每行的最后一个字符。
    
    4,删除文件每行的倒数第二个字符。
    
    5,删除文件每行的第二个单词。
    
    6,删除文件每行的倒数第二个单词。
    
    7,删除文件每行的最后一个单词。
    
    8,交换每行的第一个字符和第二个字符。
    
    9,交换每行的第一个字符和第二个单词。
    
    10,交换每行的第一个单词和最后一个单词。
    
    11,删除一个文件中所有的数字。
    
    12,删除每行开头的所有空格。
    
    13,用制表符替换文件中出现的所有空格。
    
    14,把所有大写字母用括号()括起来。
    
    15,打印每行3次。
    
    16,隔行删除。
    
    17,把文件从第2行到第5行复制到第7行后面。(选做题)
    
    18,把文件从第2行到第5行移动到第7行后面。(选做题)
    
    19,只显示每行的第一个单词。
    
    20,打印每行的第一个单词和第三个单词。
    
    21,将格式为    mm/yy/dd    的日期格式换成   mm;yy;dd
    
    22, a.txt内容
        ABC
        DEF
        XYZ
        通过SED实现tac命令
        tac a.txt
        XYZ
        DEF
        ABC
    
    1. sed -r 's/^(.)(.*)/2/' /etc/passwd
    2. sed -r 's/^(.)(.)(.*)/13/' /etc/passwd
    3. sed -r 's/(.*)(.)$/1/' /etc/passwd
    4. sed -r 's/(.*)(.)(.)$/13/' /etc/passwd
    5. sed -r 's/^([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)/124/' /etc/passwd
    6. sed -r 's/([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)$/134/' /etc/passwd
    7. sed -r 's/([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)$/123/' /etc/passwd
    8. sed -r 's/^(.)(.*)(.)$/321/' /etc/passwd
    9. sed -r 's/^(.)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)/42315/' /etc/passwd
    10. sed -r 's/^([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)$/52341/' /etc/passwd
    11. sed -r 's/[0-9]//g' /etc/passwd
    12. sed -r 's/^ *//g' /etc/passwd
    13. sed -r 's/ /	/g' /etc/passwd
    14. sed -r 's/[A-Z]/(&)/g' /etc/passwd
    15. sed 'p;p' /etc/passwd
    16. sed '1~2d' /etc/passwd
    
    选做题17-18:文件内容
    [root@MiWiFi-R3-srv ~]# cat test 
    11111111111
    2222222222
    333333333
    4444444444
    55555555555
    6666666666
    777777777777
    888888888888
    99999999999999
    
    17.sed '2h;3,5H;7G' test 
    
    18. sed '2h;3,5H;2,5d;7G' test 
    
    19. sed -r 's/^([a-Z]+)([^a-Z]+)(.*)/1/' /etc/passwd
    20. sed -r 's/^([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)/523416/' /etc/passwd
    21. 
    22. sed -r '{1h;1d;2G;2h;2d;3G;3h}'
    23. 
    echo "2012/12/11" |sed -r 's///:/g'
    echo "2012/12/11" |sed -r 's#/#:#g'
    echo "2012/12/11" |sed -r 's@/@:@g'
    复制代码

    四 awk

    awk -F: '$1 == "root"{print $1,NR,NF}' /etc/passwd awk -F: 'NR>20 || NR<3{print $1,$3,$NF}' /etc/passwd awk -F: 'NR>1 &&  NR<3{print $1,NR,NF}' /etc/passwd awk -F: 'NR>1 &&  NR<4{print $1,NR,NF}' /etc/passwd awk -F: '$1~/^r/{print $1,NR,NF}' /etc/passwd awk -F: '/^root/{print $1,NR,NF}' /etc/passwd

    username=root awk -v var=$username -F: '$1 == var{print $1,NR,NF}' /etc/passwd

    复制代码
    打印uid在30~40范围内的用户名。
    打印第5-10行的行号和用户名
    打印奇数行
    打印偶数行
    打印字段数大于5的行
    打印UID不等于GID的用户名
    打印没有指定shell的用户
    复制代码

    awk详细

    语法 awk [options] 'commands' files option -F 定义字段分隔符,默认的分隔符是连续的空格或制表符   使用option中的-F参数定义间隔符号   用$1,$2,$3等的顺序表示files中每行以间隔符号分隔的各列不同域 NF变量表示当前记录的字段数 -v 定义变量并赋值 也可以借用次方式从shell变量中引入

    command 读前处理 行处理 读后处理 1.读前处理 BEGIN{awk_cmd1;awk_cmd2} 2.行处理:定址 命令   定址方法: 正则,变量,比较和关系运算 正则需要用//包围起来 ^ 行首 $ 行尾 . 除了换行符以外的任意单个字符 * 前导字符的零个或多个 .* 所有字符 [] 字符组内的任一字符 [^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)   ^[^] 非字符组内的字符开头的行 [a-z] 小写字母 [A-Z] 大写字母 [a-Z] 小写和大写字母 [0-9] 数字 < 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词 > 单词尾

    扩展正则 加 -r 参数 或转义 sed -n '/roo?/p' /etc/passwd  sed -rn '/roo?/p' /etc/passwd   ? 前导字符零个或一个 + 前导字符一个或多个 abc|def abc或def   a(bc|de)f abcf 或 adef   x{m}   x出现m次 x{m,}  x出现m次至多次(至少m次) x{m,n} x出现m次至n次

    NR变量定址 NR 表示AWK读入的行数 FNR表示读入行所在文件中的行数 # awk '{print NR,FNR,$1}' file1  file2 1 1 aaaaa 2 2 bbbbb 3 3 ccccc 4 1 dddddd 5 2 eeeeee 6 3 ffffff # 逻辑运算 可直接引用域进行运算 == >= <= != > < ~ !~ # awk 'NR==1 {print}' /etc/passwd root:x:0:0:root:/root:/bin/bash # 3.命令 {print $0} 4.读后处理 END {awk_cmd1;awk_cmd2;}

    AWK变量 NR    当前记录的个数(全部文件连接后的统计) FNR   当前记录的个数(仅为当前文件的统计,非全部) FS    字段分隔符 默认为连续空格或制表符,可以使用多个不同的符号做分隔符 -F[:/] OFS   输出字符的分隔符 默认是空格 # awk -F: 'OFS="=====" {print $1,$2}' /etc/passwd root=====x NF    当前读入行的字段个数 ORS   输出记录分隔符 默认是换行 # awk -F: 'ORS="=====" {print $1,$2}' /etc/passwd root x=====bin x===== FILENAME 当前文件名

    引用shell变量的方法 # a=root # awk -v var=$a -F: '$1 == var {print $0}' /etc/passwd 或者 把整个命令拆开传递,让shell变量外露, # awk -F: '$1 == "'$a'" {print $0}' /etc/passwd # a=NF # awk -F: '{print $'$a'}' /etc/passwd

    操作符 赋值 = += -= /= *= 逻辑与 逻辑或 逻辑非 && || ! 匹配正则或不匹配,正则需要用 /正则/ 包围住 ~  !~ 关系 比较字符串时要把字符串用双引号引起来 < <= > >= != == 字段引用 $ 字段引用需要加$,而变量引用直接用变量名取 运算符 + - * / % ++ -- 转义序列 \ 自身 $ 转义$ 制表符  退格符 回车符 换行符 c 取消换行

    练习     打印uid在30~40范围内的用户名。     打印第5-10行的行号和用户名     打印奇数行     打印偶数行     打印字段数大于5的行     打印UID不等于GID的用户名     打印没有指定shell的用户     打印1..1000以内的7的倍数和包含7的数

    流程控制 分支结构

    if (条件) 动作 若有多个动作,则要用大括号将动作体包含起来  if (条件) {动作1;动作2} # awk -F: '{if ($1 == "root") print $1}' /etc/passwd root # # awk -F: '{if ($1 == "root") {print $1;print $6}}' /etc/passwd root /root #
    if (条件1) 动作1 else 动作2 # awk -F: '{if ($1 == "root"){print $1}else print $6}' /etc/passwd # awk -F: '{if ($1 == "root") print $1;else print $6}' /etc/passwd 上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围
    if (条件 1) 动作1 else if(条件 2) 动作2 else if(条件 3) 动作3 else 动作4 # awk -F: '{if ($1 == "root") print $1;else if ($1 == "seker") print $6;else if ($1 == "zorro") print $7;else print NR}' /etc/passwd root 2 3 ... 33 /home/seker /bin/bash 36

    条件 ? 动作1 : 动作2 expr?action1:action2 # awk -F: 'var=($3 >= 500)?$1:"system_user" {print $1" "$3" "var}' /etc/passwd # awk -F: '{print ($3>500?$1:$2)}' /etc/passwd

    练习    将系统用户按UID分组标记 0 admin; 1-499 sysuser; 500+ users awk -F: '{if($3==0) print $1" "$3" ""admin";else if($3>=1&&$3<500) print $1,$3,"sysuser";else print $1,$3,"user"}' /etc/passwd

    输出样式 %s是字符类型,%d数值类型 printf默认是不输出换行的所以要加 10和7是偏移量 默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充 注意:格式与输出列之间要有逗号 # awk -F: '{printf "%-10s %-10d %s ",$1,$3,$7}' /etc/passwd

    读前处理和读后处理 # awk -F: 'BEGIN{i=1} {i++} END {print i}' /etc/passwd 47 # # awk -F: 'BEGIN {print NR,NF}' /etc/passwd 0 0 # # awk -F: 'END {print NR,NF}' /etc/passwd 46 7 # 练习     找出普通用户的用户名并统计数量 # awk -F: 'BEGIN{i=0} $3 >= 500 {print $1;i++} END {print i}' /etc/passwd 计算UID相加的总和;计算GID相加的总和 # awk -F: 'BEGIN{i=0}{sum+=$3;i++}END{print i;print sum}' /etc/passwd         # awk -F: 'BEGIN{i=0}{sum+=$3;gsum+=$4;i++}END{print i;print sum;print gsum}' /etc/passwd 计算VSZ和RSS各自的和 并以M单位显示 #  ps aux | awk 'BEGIN{i=0}NR>=2{sum+=$5;i++}END{print sum/1024"M"}'         #  ps aux | awk 'BEGIN{i=0}NR>=2{vsum+=$5;rsum+=$6;i++}END{print vsum/1024"M";print rsum/1024"M";print i}' 循环语句 while(条件) { 动作 条件运算 } # awk -F: '{while($3<3) {print $3,$1;$3++}}' /etc/passwd 0 root 1 root 2 root 1 bin 2 bin 2 daemon # BEGIN块可以独立使用,不需要引入文件 # awk 'BEGIN{i=1;while(i<100) {print i;i++}}' 练习     打印100以内的偶数 # awk 'BEGIN{i=1;while(i<100) {if (i%2==0) print i;i++}}'
    x=1 do { 动作1 x++   } while (x<5) # awk 'BEGIN{i=5;do{print i;i++}while(i<10)}' # awk 'BEGIN{i=5;do{print i;i++}while(i<1)}'

    for(预置;条件;递增) { 动作 } # awk 'BEGIN {for (x=1;x<=4;x++) print x }' 1 2 3 4 #     # awk 'BEGIN{for (i=1;i<=4;i++) {for (j=1;j<=4;j++) print i,j}}'

    练习     使用嵌套的for循环,打印100-999之间的数,个十百位分别用一个for来打印 # awk 'BEGIN{OFS="";for (i=1;i<=9;i++) {for (j=0;j<=9;j++) {for (n=0;n<=9;n++) print i,j,n}}}' 打印乘法口诀表 # cat 99.sh #!/bin/bash awk 'BEGIN{ for(i=1;i<10;i++) { for(j=1;j<=i;j++) printf "%d*%d=%d ",j,i,j*i print }

    }' #

    打印金字塔 # cat jin.sh #!/bin/bash awk 'BEGIN{ num=5 for(i=1;i<=num;i++) { for (n=1;n<=num-i;n++) printf "%s"," " for (j=1;j<=2*i-1;j++)    printf "%s","*" print } }' #

    逆序输出每个字段 达到这样既可 /bin/bash /root root 0 0 x root

    # awk -F: '{for (x=NF;x>0;x--) print $x}' /etc/passwd

    继续解决上一个试做题的格式问题 # awk -F: '/bash$/{for (x=NF;x>0;x--) printf "%-13s",$x;printf " "}' /etc/passwd

    跳转语句 break 跳出循环 # awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}' 1 2
    continue 在达到循环底部之前终止当前循环 从新开始下一次循环 # awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}' 1 2 4

    next 读入下一行 同时返回脚本顶部 这样可以避免对当前行执行其他操作 # awk -F: 'NR > 5 {next} {print $1} END {print NR}' /etc/passwd root bin daemon adm lp 46 # exit 使读取动作终止 并将控制移动到END,如果没有END则终止脚本 # awk -F: 'NR > 5 {exit} {print $1} END {print NR}' /etc/passwd root bin daemon adm lp 6 #

    数组 自定义数组 # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";print ary[1],ary[2]}' seker zorro # # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";for(i in ary) print ary[i]}' seker zorro # 删除一个元素 对元素给空值并不能清除这个元素 要想清除一个元素需要使用delete ary[idx] # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";ary[3]="blues";ary[2]="";for(i in ary) print ary[i]}' seker

    blues # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";ary[3]="blues";delete ary[2];for(i in ary) print ary[i]}' seker blues #

    循环产生数组和取出数组 # awk 'BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}' 4 104 5 105 1 101 2 102 3 103 #
    # awk -F: '{ary[NR]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd 1 root 2 bin 3 daemon 4 adm 5 lp 6 sync 7 shutdown 8 halt 9 mail # awk -F: '{ary[$3]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd 10 uucp 11 operator 12 games 13 gopher 14 ftp 32 rpc 37 rpm

    ARGV  命令行中参数数组 # awk '{for (i in ARGV) {print i,ARGV[i]}}'  /etc/passwd /etc/fstab 0 awk 1 /etc/passwd 2 /etc/fstab #### i 为下标; ARGV[i] 下标为i的值 练习     统计每种shell被使用的次数

    函数

    算术函数 int [root@stu254 ~]# awk 'BEGIN {print int(3.9415)}' 3 [root@stu254 ~]#

    随机数函数 rand()  srand() rand() 取值 0 > r < 1 之间 默认的种子是系统时间 精确到秒 srand()取值 0 > r < 1 之间 可以指定种子来影响rand()取值数 默认是系统时间 精确到秒

    [root@stu254 ~]# awk 'BEGIN {srand(222);print int(rand()*100000000)}' 90204196 [root@stu254 ~]#

    字符串函数 substr(s,x[,y]) 返回字符串s中从位置x起至y的子串,如果没有给出y,则从x开始到结束. [root@stu254 ~]# awk 'BEGIN {x="abcdefxyz";print substr(x,4,3)}' def [root@stu254 ~]#

    大写小写 sprintf() 本身并不能打印,做格式转换,将数字转换成ASCII字符 # awk 'BEGIN {for(i=97;i<=122;++i) print tolower(toupper(sprintf("%c",i)))}'

    字符串长度 length()  如果没有给定字符串则使用$0 [root@stu254 ~]# awk 'BEGIN {print length("abcdefxyz")}' 9

    gsub(/abc/,"ABC",x) 全局字符串替换 从x中用匹配的abc正则替换成ABC [root@stu254 ~]# awk 'BEGIN {x="xyzabcxyzabcxyz";gsub(/abc/,"ABC",x);print x}' xyzABCxyzABCxyz [root@stu254 ~]#  sub 第一次的替换 [root@stu254 ~]# awk 'BEGIN {x="xyzabcxyzabcxyz";sub(/abc/,"ABC",x);print x}' xyzABCxyzabcxyz [root@stu254 ~]#

           gensub(r, s, h [, t])   Search the target string t for matches of the reg-                                ular  expression  r.   If  h is a string beginning                                with g or G, then replace all matches of r with s.                                Otherwise, h is a number indicating which match of                                r to replace.  If t is not supplied,  $0  is  used                                instead. gensub(正则,替换,范围,目标串) [root@tch254 ~]# awk 'BEGIN{print gensub("zorro","AAAA","2","seker zorro zorro seker")}' seker zorro AAAA seker [root@tch254 ~]# echo seker zorro zorro seker | sed 's/zorro/AAAA/2' seker zorro AAAA seker [root@tch254 ~]# [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","g");print}' seker AAAA AAAA seker [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","2");print}' seker zorro AAAA seker [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","h");print}' seker AAAA zorro seker [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","1");print}' seker AAAA zorro seker [root@tch254 ~]#

    系统函数 getline 

    交互输入 [root@stu254 ~]# awk -F: 'BEGIN {printf "Enter Number: ";getline ;for(i=1;i<=$0;i++) print i}' Enter Number: 3 1 2 3 [root@stu254 ~]#

    将输入赋值给变量 [root@stu254 ~]# awk -F: 'BEGIN {printf "Enter Number: ";getline NUM;for(i=1;i<=NUM;i++) print i}' Enter Number: 3 1 2 3 [root@stu254 ~]#

    从文件中读入 [root@tch254 ~]# awk -F: 'BEGIN {getline < "/etc/passwd" ; print $3" "$1}' 0 root [root@tch254 ~]#

    #awk -F: 'BEGIN {while (getline < "/etc/passwd" > 0) print $3" "$1}'

       getline < "/etc/passwd" 从文件中读入,每次读取一行,默认情况下读取的次数等于awk自身引入文件的行数    也可以放到for中来控制读取的次数 > 0    测试读取的返回值,成功返回1,失败返回-1,0文件末尾

    从命令输出中输入 [root@stu254 ~]# awk 'BEGIN {"uname -a"|getline ;print $3}' 2.6.18-53.el5 [root@stu254 ~]#

    system(command) 系统命令要用""引起来 [root@stu254 ~]# rm -rf abc/ [root@stu254 ~]# awk 'BEGIN {if(system("mkdir abc") != 0 ) print "ERR"}' [root@stu254 ~]# awk 'BEGIN {if(system("mkdir abc") != 0 ) print "ERR"}' mkdir: 无法创建目录 “abc”: 文件已存在 ERR [root@stu254 ~]# [root@tch254 ~]# awk 'BEGIN {if(system("mkdir abc 2>/dev/null") != 0 ) print "ERR"}' ERR [root@tch254 ~]# 

    awk脚本的介绍 -f 与 #!/bin/awk -f

    使用awk添加系统用户 [root@mail ~]# cat useradd.awk #!/bin/awk -f

    { system("useradd "$1";echo "$2"|passwd --stdin "$1) } [root@mail ~]# cat username myname 1234 [root@mail ~]# [root@mail ~]# ./useradd.awk ./username Changing password for user myname. passwd: all authentication tokens updated successfully. [root@mail ~]#

    复制代码
    1.使用:或/符号做分隔符,将字段逆序输出/etc/passwd文件的每行
    
    2.
    # awk -F: 'NR < 11 {print $3,$1}' /etc/passwd > name.txt
    # awk -F: 'NR < 11 {print $3,$6}' /etc/passwd > home.txt
    # join name.txt home.txt 
    观察两个文件,以及join命令输出,用awk引入name.txt,home.txt两个文件,模拟joni命令的输出
    
    3.统计/etc/passwd中每种shell的被使用人数
    输出格式:
    counts    shell
    1    
    1    /bin/sync
    4    /bin/bash
    31    /sbin/nologin
    1    /sbin/halt
    1    /sbin/shutdown
    
    4.统计ps中RSZ,VSS各自总和
    输出格式:
    ps MEM statistic
    VSZ_SUM : 164.277M
    RSS_SUM : 47.8555M
    
    
    5.计算/etc/passwd中所有用户的UID平均数,以及GID平均数.
    输出格式:
    UID and GID AVG
    UID-AVG : 1750.72
    GID_AVG : 1754
    
    6.
    根据uid值给用户分等级 Admin system users
    输出格式:
    
    LEVEL  NAME
    
    Admin    root
    sysuser    bin
    users    seker
    
    admin_count: N sys_user_count: N users_count: N 
    
    7.
    分别用GREP,SED,AWK将ifconfig中匹配到eth1的网卡所有信息打印出来.
    
    8.
    SHELL实现批量建立多个文件,将文件拓展名加上.txt,再加上.doc,再把中间的.txt去掉
    9.
    AWK脚本实现间隔五行打印表头
    [root@mail ~]# ./awk_print.sh /etc/passwd
    Username  Uid    
    root      0      
    bin       1      
    daemon    2      
    adm       3      
    lp        4      
    
    Username  Uid    
    shutdown  6      
    halt      7      
    mail      8      
    news      9      
    uucp      10     
    
    
    10.用$RANDOM产生100个随机数,交给AWK产生数组,在数组内部排序,最后输出.(禁止用sort命令)
    
    11. 建立 aa.txt 文本
    # cat aa.txt 
    aaa/bbb/ccc
    ddd/eee/fff
    ggg/hhh/iii
    aaa/bbb/ccc/aaa/bbb/ccc/ddd/eee
    # 用AWK或SED输出如下格式
    ccc aaa/bbb/
    fff ddd/eee/
    iii ggg/hhh/
    eee aaa/bbb/ccc/aaa/bbb/ccc/ddd/
    
    
    
    12. 建立 a.txt b.txt 文件
    [root@tch254 ~]# cat a.txt 
    1    a
    2    b
    3    c
    4    d
    5    e
    6    f
    7    g
    [root@tch254 ~]# cat b.txt 
    5    ABC
    3    DEF
    4    XYZ
    [root@tch254 ~]# 使用AWK处理两个文件输出如下结果
    e ABC
    c DEF
    d XYZ
    [root@tch254 ~]# 
    复制代码

    五 其他补充

    复制代码
    11111111111
    2222222222
    333333333
    4444444444
    55555555555
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    99999999999999
    99999999999999
    99999999999999
    99999999999999
    99999999999999
    99999999999999
    99999999999999
    aaaaaaaaaa
    6666666666
    777777777777
    888888888888
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    99999999999999
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    复制代码

    [root@MiWiFi-R3-srv ~]# cat test |sort |uniq #排序去重 11111111111 2222222222 333333333 4444444444 55555555555 6666666666 777777777777 888888888888 99999999999999 aaaaaaaaaa

    [root@MiWiFi-R3-srv ~]# cat /etc/passwd |cut -d: -f2

    [root@MiWiFi-R3-srv ~]# find / -size +2M -type f -name *.txt

    卓尔不凡Tony
  • 相关阅读:
    EasyNVR平台使用Onvif探测设备时的操作注意事项
    视频平台EasyNVR更新版本后视频播放不了,识别不了js是什么原因?
    EasyNVR配置连接EasyNVS无法连接,报错timeout是什么原因?
    wNAF不相邻表示形式
    密码的前情知识
    64位编译器下基本数据类型所占字节数目
    gitlab禁止用户自己删除帐号
    Python中类创建和实例化过程 勿忘
    Qt5msvc2012编译安装
    kubuntu中ibus选词窗口不能正常弹出问题人解决办法
  • 原文地址:https://www.cnblogs.com/dyytsoft/p/10524068.html
Copyright © 2020-2023  润新知