shell脚本入门

作者: JevonWei | 来源:发表于2017-06-11 15:46 被阅读27次

    一、基础知识

    编程语言有低级语言和高级语言两类。
    高级语言也有编译型和解释型的区分,编译型语言有C,C++,jave;解释型语言有shell,perl,python
    shell脚本是一种包含声明或命令,并符合一定格式的文本文件

    shell作为一种过程式解释型的编程语言,它的基本组织结构有:

    数据存储:变量、数组
    表达式
    语句:if while case
    

    shell脚本的格式有:

    #!SHEBANG    
    CONFIGURATION_VARIABLES     
    FUNCTION_DEFINITIONS    
    MAIN_CODE
    

    shell脚本格式要求首行必须是shebang机制 ,shebang也是指明文件调用的解释器类型

    #!/bin/bash     
    #!/usr/bin/python    
    #!/usr/bin/perl      
    

    运行脚本:

    给予执行权限,通过具体的文件路径指明文件执行。    
    直接运行解释器,将脚本作为解释器程序的参数运行。
    

    二、变量: 命名的存储空间

    数据的存储方式:

    字符:   
    数值:整型,浮点型 
    

    变量类型
    作用:

    1、定义数据存储格式
    2、定义参与的运算    
    3、表示的数据范围
    

    类型:

    字符    
    数值:整型,浮点数
    

    编程语言的变量又有强类型和弱类型的区分

    强类型:jave,C++
        变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换,故需要定义数据类型
    弱类型:bash
       变量会有隐式转换,故不需要指定数据类型,所有要存储的数据都当做字符进行,不支持浮点数
    

    三、逻辑运算

    与: 
        1 && 1 = 1    
        1 && 0 = 0   
        0 && 1 = 0
        0 && 0 = 0
    或: 
        1 || 1 = 1
        1 || 0 = 1
        0 || 1 = 1
        0 || 0 = 0
    非:
        !1 = 0
        !0 = 1
    异或:相同为假,不同为真 
    短路运算:
        短路与:
            第一个为0,结果必为0   
            第二个为1,第二个必须要参与运算
        短路或:
            第一个为1,结果必为1
            第一个为0,第二个必须参与运算
    

    四、bash中的变量的种类

    根据变量的生效范围为标准:

    本地变量:生效范围为当前shell进程,对当前shell之外的其他的shell进程无效,包括当前shell的子shell进程均无效;    
    环境变量:生效范围为当前shell进程及其子进程;    
    局部变量:生效范围为当前shell进程中某代码片段(通常指函数);  
    位置变量:$1,$2,...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数;    
    特殊变量:$?,$0,$*,$@,$#,$$    
    

    本地变量:

    变量赋值:name=“value”
        可以使用单引号:
            value:
                (1)可以是直接赋值:name=“filename”
                (2)变量引用:name=“$username”
                (3)命令引用:name=`COMMAND`,name=$(COMMAND)
    变量引用:$(name),$name
        "":弱引用,其中的变量引用会被替换为变量值;
        '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串;
    显示已定义的所有变量:
        set
    撤销变量:
        unset name
    

    环境变量:

    变量声明、赋值
        export name=VALUE
        declare -x name=VALUE
    变量引用:$name,$(name)
    显示所有环境变量:
        export
        env
        printenv
    撤销变量:
        unset name
    bash中有很多内置的环境变量,PATH,SHELL,UID,HISTSIZE,PWD,OLD,HISTFILE,PS1
    

    变量命名法则:

    1、不能使用程序中的保留字,如if、for
    2、只能使用数字、字母及下划线,且不能以数字开头
    3、最好见名知义
    

    只读变量:

    设置只读变量:
        readonly name
        declare -r name 
    查看只读变量:
        readonly -p 
    

    位置变量:

    在脚本代码中调用通过命令行传递给脚本的参数:
        $1,$2,....:对应调用第1,第2....个参数
             shift [n] 调换位置,n不能大于参数的个数
        $0:调用命名本身
        $*:传递给脚本的所有参数,将所有参数作为一个整体字符传递
        $@:传递给脚本的所有参数,每一个参数独立传递,与$*只有在使用“”引起来时才有区别
        $#:传递给脚本的参数个数   
    

    五、bash的配置文件

    按生效范围划分:存在两类
        全局配置:
            /etc/profile
                /etc/profile.d/*.sh
            /etc/bashrc    
        个人配置:
            ~/.bash_profile
            ~/.bashrc
    按功能划分:存在两类
        profile类:为交互式登录的shell提供配置
            全局:/etc/profile,/etc/profile.d/*.sh
            个人:~/.bash_profile
            功用:
                (1)用于定义环境变量
                (2)运行命令和脚本
       
        bashrc类:为非交互式登录的shell提供配置
            全局:/etc/bashrc
            个人:~/.bashrc
            功用:
                (1)定义命令别名
                (2)定义本地变量
    shell登录:
        交互式登录:
            直接通过终端输入账号密码;
            使用“su -UserName”或“su -l UserName”切换的用户
            读取文件的顺序:
                /etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
        非交互式登录:
            su UserName
            图形界面下打开终端
            执行脚本
            文件读取顺序:
                ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh 
    编辑配置文件定义的新配置的生效方式:
        (1)重新启动shell进程
        (2)使用source或.命令进程   
    

    六、bash中进行算数运算

    +,-,*,/,%,...
    实现算数运算:
        (1)let var=算数表达式
            sum1=3;sum2=4;let sum=$sum1+sum2
        (2)var=$(算术表达式)
        (3)var=$((算术表达式))
        (4)var=$(expr arg1 arg2 arg3...)
            sum=$(expr $num1 \* $num2)
                *在某些场景下需要转义
                
    bash有内置的随机数生成器:$RANDOM
        echo $[$RANDOM%60]  对60取模,即生成0-59之间的某个数
        echo $[$RANDOM%60+1]   取1-60之间的某数
    增强型赋值:
        +=,-=,*=,/=,%=
        count+=1  <==> count=count+1
    自增,自减:
        let var+=1 <==> let var++
        let var-=1 <==> let var--
    

    练习:
    1、编写脚本sumid.sh,计算/etc/passwd文件中的第10个用户和第20个用户的id之和
    #! /bin/bash
    user10="head -n $2 $1 | tail -n 1|cut -d: -f3"
    user20="head -n $3 $1 | tail -n 1|cut -d: -f3"
    let sum=$user10+$user20
    echo "user id sum is $sum"


    2、编写脚本/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
    #!/bin/bash
    spaceline1=grep "^[[:space:]]*$" $1 | wc -l
    spaceline2=grep "^[[:space:]]*$" $2 | wc -l
    echo "The sum of space line:$[spaceline1+spaceline2]"

    3、当执行这个脚本时会自动创建模板脚本文件,若脚本后没有跟参数则提示用户输入生成的脚本文件名,若参数大于1个,则提示参数错误并退出脚本
    #!/bin/bash
    [ $# -gt 1 ] &&{ echo "the args is error";exit;}
    [ $# == 0 ] && read -s -p "please input script name: " name || name="$1"
    echo "#!/bin/bash
    # filename "$name"
    # author:danran
    # time is date +%F" >"$name"
    chmod +x "$name"
    vim "$name"
    4、编写脚本,统计/etc、/usr、/var目录中有多少个一级子目录和文件
    #!/bin/bash
    # danran
    # time is Mon Jun 5 13:09:12 CST 2017
    line1=ls $1 | wc -l
    line2=ls $2 | wc -l
    line3=ls $3 | wc -l
    let sum=$line1+$line2+$line3
    echo $sum

    七、条件测试

    判断某需求是否满足,需要由测试机制来完成;
    Nnote:专用的测试表达式需要由测试命令辅助完成测试过程;
    测试命令:
        test EXPRESSION
        [ EXPRESSION ]
        [[ EXPRESSION ]]
        Note:EXPRESSION前后必须有空白字符
    
    bash的测试类型:
        数值测试
            -gt:大于
            -ge:大于等于
            -eq:等于
            -ne:不等于
            -lt:小于
            -le:小于等于
        字符串测试
            ==/=:等于
            >:大于
            <:小于
            !=:不等于
            ~=:左侧字符是否能被右侧的PATTERN所匹配
                Note:一般用于[[ ]]中
            -z “STRING” 测试字符串是否为空,空为真,不空为假
            -n “STRING” 测试字符串是否不空,不空为真,空为假
            eg  [ -z "$name" ]
                [[ $name ~= ^a ]]  匹配$name是否a开头
            Note:用于字符串比较时的用到的操作数都应使用引号
        文件测试
            存在性测试:
                -a:FILE   同-e
                -e:FILE:文件存在性测试,存在为真
            存在性及类别测试:
                -b FILE:是否存在且为块设备文件
                -c FILE:是否存在且为字符设备文件
                -d FILE:是否存在且为目录文件
                -f FILE:是否存在且为普通文件
                -S FILE:存在且为套接字文件
                -L FILE 或 -h FILE:存在且为链接文件
                -p FILE:是否存在且为命名管道文件
            文件权限测试:(当前用户)
                -r:文件是否存在且可读
                -w:文件是否存在且可写
                -x:文件是否存在且可执行
            文件特殊权限测试:
                -g FILE:文件存在且拥有guid权限,suid对脚本无效,脚本不是二进制文件
                -u FILE:文件存在且拥有suid权限
                -k FILE:是否存在且拥有sticky权限
            文件大小测试:
                -s FILE:文件是否存在且非空
            文件打开性测试:
                -t fd:fd表示文件描述符是否已经打开且与某终端相关
                
                -N FILE:文件自从上一次打开读取之后是否被修改过
                -O FILE:当前有效用户是否为文件属主
                -G FILE:当前有效用户是否为文件属组
            双目测试:
                FILE1 -ef FILE2:FILE1与FILE2是否指向同一个设备上的相同inode,即硬链接
                FILE1 -nt FILE2:FILE1 是否新于FILE2
                FILE1 -ot FILE2:FILE1 是否旧于FILE2    
        组合条件测试:
            逻辑运算:
                第一种方式:
                    COMMAND1 && COMMAND2    短路与
                    COMMAND1 || COMMAND2    短路或
                    ! COMMAND               非
                第二种方式:
                    [ EXPRESSION1 -a EXPRESSION2 ]   与
                    [ EXPRESSION1 -o EXPRESSION2 ]   或
                    !EXPRESSION                     非
                    必须使用测试命令进行
                [ -f /bin/cat -a -x /bin/cat ] && echo "true"
                [ ! -r /app/a -a ! -w /app/a ] && echo true <==> [ ! \( -r /app/a -o -w /app/a \) ] && echo "true"
    

    练习:
    1、编写脚本/root/bin/excute.sh,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限否则提示用户非脚本文件
    #!/bin/bash
    [ $# == 0 ] && read -p "please input fimename" name || name=$1
    [ -f $name ] && [[ "$name" =~ .sh$ ]] && chmod a+x $name || echo "$name not scripts file"
    2、编写脚本/bin/per.sh,判断当前用户对指定的参数文件,是否不可读并且不可写
    #!/bin/bash
    [ ! -r $1 -a ! -w $1 ] && echo "$1 file not read and not write"
    3、编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满
    #!/bin/bash
    inode=df -i | grep "^/dev/sd*" | tr -s ' ' '%'| cut -d'%' -f5| sort -r | head -n 1
    disk=df | grep "^/dev/sd*" | tr -s ' ' '%'| cut -d'%' -f5| sort -r | head -n 1
    [ $inode -gt 80 ] && echo "danran"
    [ $disk -gt 80 ] && echo "dan"

    八、bash自定义退出状态码

    exit [n]:自定义退出状态码为n
        Note:脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决于exit命令后面的数字n。
    Note:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行最后一条命令的状态码。
    

    练习:编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;
    如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;
    如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
    #!/bin/bash
    [ $# -lt 1 ] && (echo "please input a arge" && exit ) || echo "grep "^$" $1 | wc -l"

    相关文章

      网友评论

        本文标题:shell脚本入门

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