• shell-awk详细笔记


    shell
        # var="hexiaoqiang"
        # ${var//PATTERN/SUBSTI}:查找var所表示的字符串中,所有被PATTERN所匹配到的字符串,并将其全部替换为SUBSTI所表示的字符串;
        ${var/#PATTERN/SUBSTI}:查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;
        ${var/%PATTERN/SUBSTI}:查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;
            notice:PATTERN中使用glob风格和通配符;
        查找删除:
            ${var/PATTERN/SUBSTI}:以PATTERN为模式查找var字符串中第一次的匹配,并删除之;
            ${var//PATTERN}:以PATTERN为模式查找var字符串中的匹配,并全部删除;
            ${var/#PATTERN}:以PATTERN为模式查找var字符串行首的匹配,并全部删除;
            ${var/%PATTERN}:以PATTERN为模式查找var字符串中的匹配,并全部删除;
            ${var/%PATERN}:以PATTERN为模式查找var字符串末尾的匹配,并删除之;
        字符串大小写转换:
            ${var^^}:把var中的所有的小写字符转换为大写${var,,}:把var中的所有大写字符转换为小写;
        变量赋值:
            ${var:-VALUE}:如果var变量为空,或未设置,那么返回value;否则,则返回var变量的值;
            ${var:=VALUE}:如果var变量为空,或未设置,那么返回VALUE,并将VALUE赋值给var变量;否则,则返回var变量的值;
            ${var:+VALUE}:如果var变量不空,则返回VALUE;
            ${var:?ERRROR_INFO}:如果var为空,或未设置,那么返回ERROR_INFO为错误提示;否则,返回var值;
        练习:写一个脚本,完成如下功能
            (1)提示用户输入一个可执行命令的名称;
            (2)获取此命令所依赖的所有库文件列表;
            (3)复制命令至某目标目录(例如/mnt/sysroot,即把此目录当作根)下的对应的路径中
                bash,/bin/bash ==> /mnt/sysroot/bin/bash
                useradd,/usr/sbin/useradd ==> /mnt/sysroot/lib64/ld-linux-x8664.so.2
            
            进一步:每次复制完成一个命令之后,不要退出,而是提示用户继续输入要复制的其它命令,并重复完成如上所描述的功能;知道用户输入"quit"脚本
    bash特性:
        引用命令的执行结果:$(COMMAND) 或者 `` 反引号
        示例: mkdir $(date +%H-%M-%s)
        stat:查看文件或者文件系统的状态
        示例: stat /etc/fstab
              File: ‘/etc/fstab’
              Size: 465           Blocks: 8          IO Block: 4096   regular file
                Device: fd00h/64768d    Inode: 33554498    Links: 1
                Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
                Access: 2018-11-28 18:16:42.497510412 +0800
                Modify: 2018-11-17 23:20:14.801999430 +0800
                Change: 2018-11-17 23:26:58.495992201 +0800
                Birth: -
        linux  文件包含2类属性:
                元数据: metadata
                数据:date
        正则匹配:
            [[:upper:]] 所有的大写字母匹配
            [[:lower:]] 所有的小写字母匹配
            [[:alpha:]] 所有字母匹配
            [[:digit:]] 所有数字匹配
            [[:alnum:]] 所有字母数字匹配
            [[:space:]] 所有空白字符匹配
            [[:punct:]] 所有标点符号匹配
        [^] 匹配直指定范围外的单个字符
            [^[:upper]] 匹配任意大写字母之外的单个字符
            [^0-9]
            [^[:alnum:]] 匹配非数字字母之外的单个字符
    IO重定向及管理
        程序:指令+数据
            程序:IO
            程序的数据流有三种:
                输入的数据流: <----- 标准输入(stdin),  键盘
                输出的数据流: -----> 标准输出(stdout), 显示器
                错误输出流:  -----> 错误输出(stderr), 显示器
        fd: file descriptor 文件描述符
            标准输入 0
            标准输出 1
            错误输出 2
        输出重定向  >
            特性 覆盖输出
                    >>
            特性 追加输出
        set -C 
            禁止覆盖输出重定向向至已存在的文件
            此时可使用强制覆盖输出 >|
        set +C
            关闭上述特性  这个效果仅对当前shell有效
        错误输出流重定向:2> , 2>>
        合并正常输出流和错误输出流 
            &> , &>>
            COMMAND > /PATH/TO/SOMEFILE 2>&1
            COMMAND >> /PATH/TO/SOMEFILE 2>&1
            ----这个地方不太理解 要反复练习理解
        输入重定向 <
        tr命令
            tr [option] ... SET1 [SET2]
                把输入的数据当中的字符,凡是在set1定义范围内出现的,通通对位转换为set2出现的字符
            用法1: tr set1 set2 < /path/from/somefile
            用法2:    tr -d set1 < /path/from/somefile
            以上2中操作都不修改源文件
        Here Document : <<
            cat << EOF
            cat > /path/to/somefile << EOF 
        这个知识点很重要 很多次都没有理解 
    管道:链接程序,实现将前一个命令的输出直接定向后一个程序当做输入数据流
        COMMAND1 | COMMAND2 | COMMAND3 | ...
    tee 命令:
        COMMAND | tee /PATH/TO/SOMEFILE 既可以输出查看的文件 又保存至其他位置
        
        #!/bin/bash
        #
        cat << EOF 
        disk) show disks info
        mem) show memory info
        cpu) show cpu info
        *)QUIT
        EOF
        read -p "Your choice: " option
        if [[ "$option" == "disk" ]];then
            fdisk -l /dev/[sh]d[a-z]
        elif [[ "$option" == "mem" ]];then
            free -m
        elif [[ "$option" == "cpu" ]];then
            lscpu
        else
            echo "Unkown option"
            exit 3
        fi
        
        #!/bin/bash
        #
        for username in user21 user22 user23;do
            useradd $username
        done
        
        #求100以内所有正整数之和
        #!/bin/bash
        declare -i sum=0
        for i in {1..100};do
            echo "$sum is $sum , $i is $i"
            sum=$[$sum+$1]
            done
            
            
            
    awk命令:
        FS 默认的内置输入变量  默认为空白字符 如果在awk命令行重新定义 只需要-v 定义就可以了 
        
        示例:
            awk -v FS=':' '{print $1}' /etc/passwd   指的是以 : 为分隔符好进行打印
            awk -v FS=':' '{print "hello:",$1}' /etc/passwd
            
        上面的2条命令也可以通过-F:就可以是分隔符为:号进行打印的需求了
        awk -F: '{print "hello world: ",$1}' /etc/passwd
        OFS 内置的输出变量符 默认为空白字符 可以自定义
        FS OFS 区别主要是输入判断的变量符号 和输出表现的变量符号  比较容易理解
        
        示例
            awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
        
        RS: input record seperator   输入时的换行符
        ORS: output record seperator 输出时的换行符
        
        示例:
            awk -v RS=' ' -v ORS='#' '{print}' /etc/passwd
            awk -v RS=' ' -v ORS='#' '{print}' /var/log/messages
            解释:输入的时候以空格为换行符 然后输出的时候 有空格的时候就会转换为#号 这个地方不好理解
            
        NF: number of field 字段数量 记录每行以默认空格计算有多少字段
            示例:
                awk '{print NF}' /etc/log/messages
                awk '{print NF}' /etc/passwd
        $NF: NF会得到每行以空格计算有多好字段 然后拿到这个字段数 然后打印这个字段的值
             取字段变量的最后一个值
             示例:
                awk '{print $NF}' /var/log/messages
    awk 内部引用变量不需要加$ 直接引用即可    
        NR: 记录文件的行数 后面跟多个文件的时候 继续增加行数 而是不区分文件进行计数
            示例:
                awk '{print NR}' /etc/passwd
                awk '{print NR}' /var/log/messages /etc/passwd
                awk -F: '(NR>=2&&NR<=10) {print $1}' /etc/passwd
        FNR: awk后面跟多个文件的时候 分别记录文件的行数        
            示例:
                awk '{print FNR}' /etc/fstab /etc/passwd
        FILENAME 显示文件名 一个文件要是有多少行 就会显示多少遍
            示例:
                awk '{print FILENAME}' /etc/fstab /etc/passwd  不建议常用 但是思想是可以遍历文件多少行 每行都会处理
        ARGC: 命令行参数的个数
            示例:
                awk '{print ARGC}' /etc/passwd /etc/issue /etc/fstab 记录命令行参数的个数 awk和自己的参数算只能算一个 文件有多少行就会显示多少遍
                awk 'BEGIN{print ARGC}' /etc/passwd /etc/fstab /etc/issue 在打印前面加BEGIN就会只显示一遍
        ARGV: 数组,保存的是命令行所给定的各参数
            示例:
                awk '{print ARGV[0]}' /etc/passwd /etc/fstab /etc/issue 只会打印awk这个下标的数组 不加BEGIN的时候文件有多少行就会显示多少遍
                awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2],ARGV[3]}' /etc/passwd  /etc/fstab /etc/issue /var/log/messages 在前面print添加BEGIN之后就只显示一遍 根据下标打印相对应的数组值
    2.2自定义变量
        -v var=value
            变量名区分大小写
        在program中直接定义
        示例:
            awk -v test="hello world" '{print test}' /etc/fstab 
            awk -v test="hello world" 'BEGIN{print test}' /etc/fstab
            print 打印变量的时候直接引用变量名 /etc/fstab 这个地方值利用的是行数 文件有多少行就会打印多少遍hello world 前面加BEGIN的时候只会打印一遍了
            awk '{test="hello world";print test}'   可以在print中直接定义变量
            awk 'BEGIN{test="hello world";print test}' /etc/fstab
    2.3 printf 命令
        格式化输出: printf FORMAT,item1,item2,...
            FORMAT必须给出
            printf不会自动换行,需要显示给出换行控制符,n
            FORMAT 中需要分别为后面的每个item指定一个格式化符号
            
            格式符:
                %c: 显示字符的ASCII码
                %d %i: 显示十进制整数 decimal intege 单词可能不太准确
                %e %E: 科学计数法数值显示
                %f: 显示为浮点数
                %g %G: 以科学计数法或浮点形式显示数值
                %s: 显示字符串
                %u: 无符号整数
                %%: 显示%自身
        示例:
            awk -F: '{printf "%s",$1}' /etc/passwd    把$1套到%s进行以字符串进行显示 默认不加换行符就会显示在一行中
            awk -F: '{printf "%s
    ",$1}' /etc/passwd  n就会每一行只显示一个用户名
            awk -F: '{printf "Username: %s
    ",$1}' /etc/passwd  还可以加前缀提示字符进行显示
            awk -F: '{printf "Username: %s,UID: %i
    ",$1,$3}' /etc/passwd
            awk -F: '{printf "Username: %s,UID: %i
    ",$1,$3}' /etc/passwd        第一个%s后面不能加
    不然每一行都会在2行进行显示了 在最后一个FORMAT定义的变量之后加n符号 这个是显示 用户名和UID  %d %i 都是以数值的方式显示用户的UID
        修饰符:
            #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;
                %3.1f 默认这样的使用 以f居多
                默认对齐方式为右对齐
                
                示例:
                    awk -F: '{printf "Username: %15s,UID: %d
    ",$1,$3}' /etc/passwd 
                    
            -: 表示左对齐
                示例:
                    awk -F: '{printf "Username: %-15s,UID: %d
    ",$1,$3}' /etc/passwd
                    
            +: 显示数值的符号 正数的时候前面会有+号
                
                示例:
                    awk -F: '{printf "Username: %15s,UID: %+d
    ",$1,$3}' /etc/passwd
    4.操作符
        算数操作符
        
        x+y, x-y, x*y, x/y, x^y[x的y次方], x%y[取模] 
        -x
        +x:转换为数值 [把字符串转换为数值]
        字符串操作符:没有符号的操作符,表示字符串连接
        赋值操作符:
            =,+=,-=, *=, /=, %=, ^=
            ++, --
        比较操作符:
            >, >=, <, <=, !=, ==
        模式匹配符:
            ~:左侧的字符是否能匹配右侧的字符
            !~:左侧的字符不匹配右侧的字符
        逻辑操作符:
            && 与
            || 或
            ! 非
        函数调用:定义函数 后面跟上()就可以了  ()里面可以加上调用的参数
            
            function_name(argu1,argu2,argu2,...)
            
        条件表达式:
            
            selector:条件挑选器
            ?:表示为真执行 if-true-expression
                否则执行 if-false-expression
            
            示例:
                selector?if-true-expression:if-false-expression
                awk -F: '{$3>1000?usertype="Common User":usertype="System or Systemuser";printf "%15s:%-s
    ",$1,usertype}' /etc/passwd
                解释:-F: 定义打印格式 $3>1000 判断第三个字段是否大于1000 然后定义条件表达式 格式上面有解释,以:为分隔符进行判断 第一个为真后面就会打印 第二个为假后面会打印 字段使用双引号进行包含 printf 开始匹配打印 "15%s:%-s
    " printf的打印格式 %s默认为右对齐 15表示15个空格 %-s表示左对齐 $1是取字段第一个值 usertype是调用定义的变量字符串进行打印 后面是需要的条件输入文件位置
    5、PATTERN
        (1) empty:孔模式,匹配每一行
        (2) /regular expression/:仅处理能够被此处的模式匹配到的行
        (3) relational expression:关系表达式:结果有"真"有"假":结果为"真"才会被处理;
            真:结果为非0值,非空字符串
        (4) line ranges:行范围
            startline,endline: /pat1/,/pat2/
            注意:不支持直接给出数字的格式
            
            示例:
                awk '/^UUID/{print $1}' /etc/fstab 在这儿就能实现UUID匹配行的打印 打印第一个字段 默认的变量还是以空格为分割
                awk '!/^UUID/{print $1}' /etc/fstab  打印匹配模式以外的行 然后打印第一个字段
                awk -F: '$3>100{print $1,$3}' /etc/passwd $3>100是进行模式匹配 然后再后面打印 就可以实现类似grep的功能了
                awk -F: '$3>100{printf "%15s:%-s
    ",$1,$3}' /etc/passwd
                awk -F: '$3<100{printf "%15s:%-s
    ",$1,$3}' /etc/passwd
                awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd 查找/etc/passwd中shell为/bin/bash的用户
                awk -F: '$NF~/bash$/{print $1,$NF}' /etc//passwd $NF模式匹配 ~进行模式匹配 匹配的内容要用//括起来 /bash$/以bash结尾的用户
                awk -F: '$NF!~/bash$/{print $1,$NF}' /etc//passwd 不以/bash$/结尾的在$NF后面加一个!就可以
                awk -F: '/^r/,/^s/{print $1}' /etc/passwd /pat1/,/pat2/ 模式匹配 从r字母开头的行匹配到s开头的行结束
                awk -F: 'BEGIN{print "    username    uid     
    ---------------"}{print $1,$3}' /etc/passwd BEGIN 和 END的使用方法
                awk '/^[[:space:]]*linux16/{print}' /etc/grub2.cfg 打印这个文件中以开头为空格的字符 然后后面匹配Linux16的行
        (5) BEGIN / END 模式
            BEGIN{}: 仅在开始处理文件中的文本之前执行一次;
            END{}:仅在文本处理完成之后执行一次;
            
                示例:
                  awk -F: '{print "    username    uid     
    ---------------"}{print $1,$3}END{print "=====================
           end"}' /etc/passwd END用在最后进行使用 打印结尾 表示
    6. 常用的action
        (1) Expressions
        (2) Control statements: if while等:
        (3) Compound statements:组合语句
        (4) input statements
        (5) output statements
    7. 控制语句
        if(condition) {statements}
        if(condition) {statements} else {statements}
        while(condition) {statements}
        do {statements} while{condition}
        for(expr1;expr2;expr3) {statements}
        break
        continue
        delete array[index]
        delete array
        exit
        {statements}
        
        7.1 if-else
            
            语法:if(condition) {statements} else {statements} 使用场景:对awk取得的整行或某个字段做条件判断
            示例:        
            awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
            awk -F: '{if($3>100) print $1,$3}' /etc/passwd
            awk -F: '{if($3>100) {printf "Common user: %s
    ",$1} else {printf "root or Systemuser: %s
    ",$1}}' /etc/passwd
            if-else的时候要把{prinf}都用大括号个括住了 不然会报语法错误
            awk '{if(NF>5) print $0}' /etc/fstab 对字段数大于5的进行print
            df -Th | awk -F[%] '/^/dev/{print $1}' | awk '{if($NF>4) print $1}'
        7.2 while 循环
    
            示例:
                awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
                awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) print $i,length($i);i++}}' /etc/grub2.cfg 嵌套if循环判断
        7.3 do-while循环
            语法:do statement while(condition)
                意义:至少执行一次循环体
        7.4 for循环
            语法: for(expr1;expr2;expr3) statement
                for(variable assignment;condition;iteration process) {for-body}
            awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
            
            特殊用法:
                能够遍历数组中的元素:
                    语法:for(var in array) {for-body}
        7.5 switch语句
            语法: switch(expression) {case VALUE1 or /REGEXP1/: statement;case VALUE2 or /REGEXP2/: statement;...;default: statement}
        7.6 break和continue
            break [n] 退出n层循环
            continue
        7.7 next
            提前结束对本行的处理而直接进入下一行;
            示例:
                awk -F: '{if($3%2!=0) next; print $1,$3}' /etc//passwd
    8.array
        关联数组:array[index-expression]
        index-expression    
            (1)可使用任意字符串:字符串要使用双引号;
            (2)如果某数组元素事先不存在,在引用时,awk会自动创建,并将其初始化为"空串";
            若要判断数组中是否存在某元素,要使用"index in array" 格式进行
            weekdays[mon]="Monday"
            若要遍历数组中的每个元素,要使用for循环;
                for(var in array) {for-body}
                示例:
                    awk 'BEGIN{weekdays["mon"]="moday";weekdays["tue"]="Tuesday"; for(i in weekdays) {print weekdays[i]}}'
                    注意: var会遍历array的每个索引
                    使用场景:统计打印结果中某个字符串出现的次数
                    netstat -ntlp | awk '/^tcp>/{state[$NF]++}END { for(i in state) {print i.state[i]}}'
                    awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log 统计ip访问的次数 俗称报告生成器
                    awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab  统计系统文件类型出现的次数
                    awk '{for(i=1;i<NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab  统计文件单词出现的次数
                        {for(i=1;i<NF;$i++){count[$i]++}} 使用for循环做定义判断  NF记录的是文件字段出现的次数  count[$i]++ 则是使用$i下标进行统计次数 每次+1
    9.函数
        9.1内置函数
            函数处理;
                rand();返回0和1直接的随机数 awk在系统第一次打印时 是随机的而后的打印都是保持第一次的随机数
            字符串处理;
                length([s]): 返回指定字符串的长度
                sub(r,s,[t]): 以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容  这个只会替换第一次替换不会 全局进行替换
                gsub(r,s,[t]):表示全局进行替换
                
                示例:
                     awk -F: '{print sub(o,O,$1)}' /etc/passwd  使用print的时候会打印结果1表示不成功 0表示成功
                
                split(s,a,[r]) : 以r为字符切割字符s,并将切割后的结果保存至a所表示的数组中
                    
                    示例:
                    netstat -tan | awk '/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count) {print i,count[i]}}'
                    详解: {split($5,ip,":")} 以第5个字段进行切割保存至ip数组中,":"以分隔符进行切割
                          ip[1] 是以":"切割之后拿到左面第一个字段的值
                          count[ip[1]]++ 拿到左面第一个字段下表的记录 每次都+1 做数组循环
                          {split($5,ip,":");count[ip[1]]++}END最后只打印一次
                          {for(i in count) {print i,count[i]}} 做数组循环判断进行打印结果
  • 相关阅读:
    MySQL服务器变量:MySQL系列之八
    存储引擎:MySQL系列之七
    用户与授权:MySQL系列之六
    视图、存储函数、存储过程、触发器:MySQL系列之五
    SQL语法:MySQL系列之四
    关系型数据库基础概念:MySQL系列之开篇
    基础篇:MySQL系列之三
    多实例:MySQL系列之二
    安装篇:MySQL系列之一
    DNS
  • 原文地址:https://www.cnblogs.com/S--S/p/10177047.html
Copyright © 2020-2023  润新知