zoukankan      html  css  js  c++  java
  • 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]}} 做数组循环判断进行打印结果
  • 相关阅读:
    7.21 高博教育 数组 内存
    【基础扎实】Python操作Excel三模块
    PAT 甲级 1012 The Best Rank
    PAT 甲级 1011  World Cup Betting
    PAT 甲级 1010 Radix
    链式线性表——实验及提升训练
    循环程序设计能力自测
    链表应用能力自测
    PAT 甲级 1009 Product of Polynomials
    1008 Elevator (20分)
  • 原文地址:https://www.cnblogs.com/S--S/p/10177047.html
Copyright © 2011-2022 走看看