Shell编程

作者: kangapp | 来源:发表于2019-03-12 16:49 被阅读0次
    字符串处理
    • 计算字符串长度
      方法1:${#变量}
      方法2:expr length "$变量" (如果内容有空格,则必须加上" ")

    • 获取字符索引的位置
      expr index "$变量" 字符
      例:expr index "$string" str('str'在string中的索引位置,str拆分成3个字符,返回找到第一个字符的位置)

    • 获取匹配子串的长度
      expr match "$变量" 子串(必须要从头开始匹配,否则会返回0)

    • 抽取字符串中的子串
      方法1:
      ${变量:position}索引从0开始
      ${变量:position:length}
      ${变量: -position:length}或${变量:(-position):length}索引从-1开始
      方法2:
      expr substr "$变量" position length 索引从1开始

    • 需求描述:

    变量string="Bigdata process framework is Hadoop,Hadoop is an open source project",执行脚本后,打印输出string字符串变量,并给出用户以下选项:

    • 打印string长度
    • 删除字符串中所有的Hadoop
    • 替换第一个Hadoop为Mapreduce
    • 替换全部Hadoop为Mapreduce
      用户输入数字1|2|3|4,可以执行对应项的功能;输入q|Q则退出交互模式
      1 #!/bin/bash
      2 #
      3 
      4 function print_tips
      5 {
      6     echo "********************************"
      7     echo "(1) 打印string长度"
      8     echo "(2) 删除字符串中所有的Hadoop"
      9     echo "(3) 替换第一个Hadoop为Mapreduce"
     10     echo "(4) 替换全部Hadoop为Mapreduce"
     11     echo "用户输入数字1|2|3|4,可以执行对应项的功能;输入q|Q则退出交互模式"
     12     echo "********************************"
     13 }
     14 
     15 function len_of_string
     16 {
     17     echo "string长度:${#string}"
     18 }
     19 
     20 function delete_all_Hadoop
     21 {
     22     echo "${string//Hadoop/}"
     23 }
     24 
     25 function replace_first_Hadoop
     26 {
     27     echo "${string/Hadoop/Mapreduce}"
     28 }
     29 
     30 function replace_all_Hadoop
     31 {
     32     echo "${string//Hadoop/Mapreduce}"
     33 }
     34 
     35 string="Bigdata process framework is Hadoop,Hadoop is an open source project"
     36 
     37 while true
     38 do
     39     echo "【string:$string】"
     40     print_tips
     41     read -p "please input your choice [1|2|3|4|Q|q]:" choice
     42     case $choice in
     43         1)
     44             len_of_string
     45             ;;
     46         2)
     47             delete_all_Hadoop
     48             ;;
     49         3)
     50             replace_first_Hadoop
     51             ;;
     52         4)
     53             replace_all_Hadoop
     54             ;;
     55         Q|q)
     56             exit
     57             ;;
     58         *)
     59             echo "请按提示输入正确的指令"
     60     esac
     61 done
    
    命令替换

    方法1:`command`
    方法2:$(command)

    • 获取系统的所用用户并输出
      1 #!/bin/bash
      2 #
      3 
      4 index=1
      5 
      6 for user in `cat /etc/passwd | cut -d ":" -f 1`
      7 do
      8     echo "user${index}:${user}"
      9     index=$(($index + 1))
     10 done
    
    有类型变量
    • declare / typeset
    bash数学运算expr

    提示用户输入一个正整数num,然后计算1+2+3+....+num的值,必须对num是否为正整数做一个判断,不符合当允许重新输入。

    
      1 #!/bin/bash
      2 #
      3 
      4 while true
      5 do
      6     read -p '请输入一个正整数:' num
      7     expr $num + 1 &> /dev/null
      8     if [ $? == 0 ];then
      9         if [ `expr $num \> 0` == 1 ]; then
     10             for ((i=1;i<=$num;i++))
     11             do
     12                 sum=`expr $sum + $i`
     13             done
     14             echo "1+2+...+$num=$sum"
     15             exit
     16         else
     17             echo "输入的不是正整数"
     18         fi
     19     else
     20         echo "输入格式错误!!!!"
     21     fi
     22     continue
     23 done
    
    bc

    bash内建运算器,支持浮点数运算

    • 输入bc 直接进入交互模式
    • 传参 echo "scale=3;8/3"|bc
    函数
    • 函数的定义
    //第一种
    function_name() 
    {
      //todo
    }
    //第二种
    function function_name
    {
      //todo
    }
    
    • 向函数传递参数
      函数传参和脚本脚本传参类似,都是使用12.....

    写一个脚本,该脚本可以实现计算器的功能,可以进行四则运算

      1 #!/bin/bash
      2 #
      3 
      4 function calculator
      5 {
      6     case $2 in
      7         +)
      8             echo "$1+$3=`expr $1 + $3`"
      9             ;;
     10         -)
     11             echo "$1-$3=`expr $1 - $3`"
     12             ;;
     13         \*)
     14             echo "$1*$3=`expr $1 \* $3`"
     15             ;;
     16         /)
     17             echo "$1/$3=`expr $1 / $3`"
     18             ;;
     19     esac
     20 }
     21 
     22 calculator $1 $2 $3
    

    todo:*号不能作为参数传递

    • 函数的返回值
      1、return
      只能返回0-255的整数,通常用来表示状态
      function_name && echo "ok" || echo "faile"
      返回值为0则表示成功
      2、echo
      可以返回任何字符串结果
      严格上不能算返回值,可用 ``来获取echo的值
    • 全局变量和局部变量
      函数内定义的变量默认是全局变量,local修饰则为局部变量
    • 函数库
      定义库函数文件base_function.lib
    function add
    {
        echo "`expr $1 + $2`"    
    }
    
    function reduce
    {
        echo "`expr $1 - $2`"
    }
    
    function mul
    {
        echo "`expr $1 \* $2`"
    }
    
    function div
    {
        echo "`expr $1 / $2`"
    }
    
    function sys_load
    {
        echo "Memory Info"
        echo
        free -m
        echo
    
        echo "Disk Usage"
        echo
        df -h
        echo
    }
    

    . bash_function.lib(加点引用),shell中取绝对路径
    可以直接使用库函数 :add 3 4

    find 命令

    语法格式:find [路径] [选项] [操作]

    选项
    • -name,-iname(忽略大小写)) find /etc -name '*conf'
    • -user,-group)
    • -type find . -type f
      f 文件
      d 目录
      l 链接文件
      ...
    • -size)
      -n 大小大于n的文件
      +n 大小小于n的文件
      查找/etc目录下小于1000字节的文件:find /etc -size -1000c
      查找/etc目录下大于1M的文件:find /etc -size +1M
    • -mtime,mmin)
      -n n(天,分钟)以内修改的文件
      +n n(天,分钟)以外修改的文件
    • -mindepth n(表示从n级子目录开始搜索,命令紧接目录)
      find /etc -mindepth 3
    • -maxdepth n(表示最多搜索到n级子目录)
    命令
    • -print(默认))
    • -exec(对搜索到的文件执行特定的操作)) -exec 'command' {} \

    将/var/log/目录下以log结尾的文件,且更改时间在7天以上的复制到/root/conf/目录下
    find /var/log/ -type -f -name '*log' -mtime +7 -exec cp {} /root/conf/ \;

    locate命令

    在数据库文件中查找
    更新数据库updatedb

    whereis命令
    • -b 返回二进制执行文件
    • -m 返回帮助文档文件
    • -s 返回源代码文件
    which命令
    • -b 只返回二进制程序文件
    grep命令

    语法格式:
    grep [option] [pattern] [file1,file2....]
    command | grep [option] [pattern]

    option
    • -v 不显示匹配行信息
    • -i 忽略大小写
    • -n 显示行号
    • -r 递归搜索
    • -E 支持扩展正则表达式
    • -F 按照字符串字面意思匹配
    • -c 只输出匹配行的数量
    • -w 匹配整词
    • -x 匹配整行
    • -l 只列出匹配的文件名,不显示具体内容
    sed命令

    语法格式:
    sedout | sed [option] "pattern command"
    sed [option] "pattern command" file

    option
    • -n 只打印模式匹配行
    • -e 直接在命令行进行sed编辑,默认选项,当有两个或以上的命令时,每个命令前都要加-e
    • -f 编辑动作保存在文件中,指定文件执行
    • -r 支持扩展正则表达式
    • -i 直接修改文件内容
    pattern 匹配模式
    • 10command:匹配到第10行
    • 10,20command:匹配10到20行
    • 10,+5command:匹配10到15行
      sed -n '10,+5p' test.sec
    • /pattern/command:匹配到pattern的行,支持基础正则
      sed -n '/^root/p' /etc/passwd
    • /pattern1/,/pattern2/command
    • /pattern1/,10command
    • 10,/pattern1/command
      匹配范围:如果找不到匹配的行会打印所有,数字结尾则打印开始匹配的一行
      sed -n '/^root/,/^uucp/p' /etc/passwd
    command 编辑命令

    打印

    • p 打印

    增加

    • a 行后追加
      sed -i '/\/bin\/bash/a This is a user which can login' passwd
    • i 行前追加
    • r 外部文件读入,行后追加
      sed -i '/^kang/r ./insert.txt' passwd
    • w 匹配行写入外部文件
      sed -i '/\/sbin\/nologin/w ./nologin.txt' passwd

    删除

    • d 删除
      sed -i '/^root/,/^uucp/d' passwd

    修改

    • s/old/new 将行内第1个old替换为new
    • s/old/new/2 将行内第2个old替换为new
    • s/old/new/g 将行内全部的old替换为new
    • s/old/new/2g 将行内第2个及以后old替换为new
    • s/old/new/ig 将行内old全部替换为new,忽略大小写
      sed -i 's/This is a user which can login/yes I am/g' passwd
    • 反向引用
      &:&只表示匹配到的完整字符串
      sed -i 's/he..o/\<&\>/g' test.txt
      \1:可以取匹配字符串的()括起来的部分
      sed -i 's/\(he.\).o/\1qqq/g' test.txt

    案例1:输入mysql的my.cnf文件,根据段名输出该段包含项的数量
    1 mysqld 4
    2 mysqld_safa 2

      1 #!/bin/bash
      2 #
      3 
      4 MYSQLCONF_NAME=/root/linux_test/test/my.cnf
      5 
      6 function get_all_segments
      7 {
      8     echo "`sed -n '/\[.*\]/p' $MYSQLCONF_NAME|sed -e 's/\[//g' -e 's/\]//g' `"
      9 }
     10 
     11 function count_items_in_segment
     12 {
     13     sum=`sed -n '/\['$1'\]/,/\[.*\]/p' $MYSQLCONF_NAME|grep -v '\[.*\]'|grep -v '^$'|grep -v '^#'|wc -l`
     14     echo "$sum"
     15 }
     16 
     17 index=0
     18 for item in `get_all_segments`
     19 do
     20     index=`expr $index + 1`
     21     echo "$index:$item  `count_items_in_segment $item`"
     22 done
    

    案例二:删除配置文件中的所有注释行和空行
    sed -i '/[:blank:]*#/d' nginx.conf

    案例三:在配置文件中所有不以#开头的行前面添加*符号
    sed -i 's/^[^#]/\*&/g nginx.conf'

    awk命令

    语法格式:
    awk -f 文件名
    awk 'BEGIN{}pattern{commands}END{}' file_name
    standard output | awk 'BEGIN{}pattern{commands} END{}'

    内置变量
    • $0 整行内容
    • 1-n 当前行的第1-n个字段
    • NF 当前行的字段个数,即有多少列
    • NR 当前行的行号,从1开始计数
    • FNR 多文件处理是,每个文件行号单独计数,从1开始
    • FS 输入字段分隔符,不指定默认以空格或tab键分割
    • RS 输入行分隔符,默认回车换行
    • OFS 输出字段分隔符,默认为空格
    • ORS 输出行分隔符,默认回车换行
    • FILENAME 当前输入的文件名字
    • ARGC 命令行参数个数
    • ARGV 命令行参数数组
    printf
    格式符 含义
    %s 打印字符串
    %d 打印十进制数
    %f 打印浮点数
    %x 打印十六进制数
    %o 打印八进制数
    %e 打印数字的科学计数法
    %c 打印单个字符的ASCII码
    %s 打印字符串

    awk 'BEGIN{FS=":"} {printf "0.2%f\n",$3}' /etc/passwd

    修饰符 含义
    - 左对齐(默认右对齐)
    # 显示8进制在前面加0,显示16进制在前面加0x

    awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
    awk 'BEGIN{FS=":"} {printf "%-12d\n",$3}' /etc/passwd

    pattern模式匹配
    • 正则表达式匹配

    匹配/etc/passwd文件行中含有root字符串的所有行
    awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
    匹配/etc/passwd文件行中以yarn开头的所有行
    awk 'BEGIN{FS=":"}/^yarn/{print $0} /etc/passwd'

    • 关系运算匹配(> < == >= != ~匹配正则 !~ )

    匹配/etc/passwd文件行中第3个字段小于50的所有行
    awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
    匹配/etc/passwd文件行中第7个字段等于/bin/bash的所有行
    awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
    匹配/etc/passwd文件行中第3个字段包含3个以上数字的所有行
    当出现{x,y}次数匹配,需加上--posix或--re-interval
    awk --posix 'BEGIN{FS=":"} $3~/[0-9]{3,}/{print $0}' /etc/passwd

    • 布尔运算符(&& || !)

    匹配/etc/passwd文件行中第1个字段包含hdfs或yarn的所有行
    awk 'BEGIN{FS=":"}$1=="hdfs"||$1=="yarn"{print $0}' /etc/passwd
    匹配/etc/passwd文件行中第3个字段和第4个字段同时包含3个以上数字并且的所有行
    awk --re-interval 'BEGIN{FS=":"} $3~/[0-9]{3,}/&&$4~/[0-9]{3,}/{print $0}' /etc/passwd

    条件表达式和循环表达式

    awk 'BEGIN{FS=":"}{if($3>50) {print "$3>50",$3} else {print "$3<50",$3}}' /etc/passwd
    三种循环(while/ do while/ for())
    awk '{num=NF-1;for(i=2;i<=NF;i++){sum=sum+$i};AVG=sum/num;sum=0;print AVG}' ipAddress

    字符串函数
    函数 功能
    length(str) 计算长度
    index(str1,str2) 返回str1中查询到的str2的位置
    tolower(str) 小写转换
    toupper(str) 大写转换
    split(str,arr,fs) 分割字符串,并保存到arr中,返回数量
    match(str,RE) 返回正则表达式匹配到的子串位置
    substr(str,m,n) 截取子串,从m开始截取n位
    sub(RE,RepStr,str) 替换查找到的第一个子串,返回替换的个数
    gsub(RE,RepStr,str) 替换查找到的所有子串,返回替换的个数

    以:为分隔符,返回/etc/passwd中每行的各个字段的长度
    awk '{num=split($0,arr,":");for(i=1;i<=num;i++){printf "%d ",length(arr[i])};print ""}' /etc/passwd

    [option]
    • -v 定义或引用变量
      awk -v a="$PATH" -v b="$JAVA_HOME" 'BEGIN{print a,b}'
    • -f 指定awk命令文件
    数组
    • shell中的数组
      arr=("dfdf" "wew" "eweedv")
      打印元素,下标从0开始:echo ${arr[0]}
      打印元素个数:echo ${#arr[@]} echo ${#arr[*]}
      给元素赋值:arr[1]="xxxx"
      删除元素,元素下标不变:unset arr[2] unset arr
      分片访问:echo ${arr[@]:1:3}
      元素内容替换:第一个echo ${arr[*]/a/A} 全部echo ${arr//a/A}
      数组的遍历:for i in ${arr[@]} do xxx done
    • awk中的数组
      默认为数字下标,从1开始
      awk 'BEGIN{str="mike ammy jack tom";split(str,arr);for(i=1;i<=length(arr);i++){print arr[i]}}'
      也可以字符串为下标,推荐使用
      awk 'BEGIN{arr["var1"]="jack";arr["var2"]="mike";for(i in arr) print arr[i]}'

    统计主机上所有Tcp连接状态数,按照每个Tcp状态分类
    netstat -an | grep tcp | awk '{array[$6]++}END{for(i in array) print i,array[i]}'

    计算横向数据综合,计算纵向数据总和

      1 BEGIN{
      2     printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","name","A","B","C","D","AVG"
      3 }
      4 {
      5     printf "%-8s",$1
      6     sum=0;
      7     avg=0;
      8     for(i=2;i<=5;i++)
      9     {
     10         printf "%-8d",$i
     11         sum=sum+$i
     12         array[i]=array[i]+$i
     13     };
     14     avg=sum/NF
     15     printf "%-8.2f\n",avg
     16 }
     17 END{
     18     printf "%-8s%-8d%-8d%-8d%-8d\n","Total",array[2],array[3],array[4],array[5]
     19 }
    

    相关文章

      网友评论

        本文标题:Shell编程

        本文链接:https://www.haomeiwen.com/subject/eqwaeqtx.html