zoukankan      html  css  js  c++  java
  • Linux系统——shell脚本

    shell脚本编程

    作用:通过命令行解析的方式,自动执行设定好的程序或命令代码。(若将脚本挂到定时任务中,就会自动在非工作时间里自动触发执行程序)

    Shell脚本文件.sh”结尾

    规范的Shell脚本第一行会指出由哪个程序(解释器)来执行脚本中的内容。在linux bash编程中一般为:#!/bin/bash (表示该脚本运用/bin/bash命令进行解析)

    Shell的输出用echo命令;

    Python的输出用print命令

    执行脚本的方式:

    方法一:/bin/shbash的软链接,也就是说我么既可以用sh执行也可以用bash执行脚本

    # sh yunjisuan.sh

    # bash yunjisuan.sh

    方法二:以绝对路径的方式执行脚本(前提:将该脚本添加x执行权限 )

    # chmod +x yunjisuan.sh

    # /root/benet/yunjisuan.sh

     

    方法三:以source脚本路径的方式执行脚本(等同于“.脚本路径” )只在当前环境生效

    # source yunjisuan.sh

    # . yunjisuan.sh

    方法四:以相对路径的方式执行脚本(前提:将该脚本添加x执行权限 )

    # ./yunjisuan.sh

    写脚本

    (1)vim编辑yunjisuan.sh

    (2)查看yunjisuan.sh脚本

     

    (3)执行yunjisuan.sh脚本

    脚本中书写的命令必须是非交互式的命令!!!

    虽然脚本可以自动化执行,但脚本不会判断命令是否执行成功,因此需要进行逻辑判断

    方法一:

    test命令

    判断该字符串表示为文件还是目录

    -d 测试是否为目录

    -e 测试目录或文件是否存在

    -f 测试是否为文件

    -l 测试是否为链接文件

    -r 测试当前用户是否可读

    -w 测试当前用户是否可写

    -x 测试当前用户是否可执行

    -s 测试文件大小非0时为真(若为非空文件,则为真)

    -u 测试是否具有SUID属性

    -g 测试是否具有SGID属性

    -k 测试是否具有sticky bit 粘滞位属性

    -z 测试字符串是否为空(zero

    file1 -nt file2测试第一个文件是否比第二个文件新(new then

    file1 -ot file2 测试第一个文件是否比第二个文件旧(old then

    file1 -ef file2 测试第一个文件是否与第二个文件为同一个文件(link之类的文件)

    # test -d 目标路径

    # echo $?判断是否是目录,若显示0表示真(是目录),若显示非0则假(不是目录)

    # test -f 目标路径

    判断目标是不是文件

    # echo $?

    $?返回值参考

    0 表示运行成功

    2 权限拒绝

    1125 表示运行失败,脚本命令,系统命令错误或参数传递错误;

    126 找到该命令,但无法执行

    127 未找到要运行的命令

    128 命令被系统强制结束

     

    方法二:

    使用[]”,表示开启判断条件(“[]”两边须有空格)

    # xx=”welcome”

    # [ $xx == welcome] && echo “0” || echo “1”

    0

    []”应用于整数 (格式:整数1 操作符 整数2

    -gtgreat than)表示大于

    -ltless than)表示小于

    -eqequal)表示等于

    -ne not equal)表示不等于

    -ge 表示大于等于

    -le表示小于等于

    && 逻辑与,表示前一指令为真,执行后一指令,否则不执行

    || 逻辑或,表示前一指令为假,执行后一指令,否则不执行

    # xx=”44”

    # if [ -f "$file1" ];then echo 1;else echo 0;fi

    相当于# [ -f "file1" ] && echo 1 ||echo 0

    # [ $xx -eq 34 ] && echo “0” || echo “1”

    1

    字符串测试

    [ -z “字符串” ]  字符串内容为空

    [ -n “字符串” ]  字符串内容不为空

    ${#变量名}   求变量的字符串位数,判断字符串是否为空

    # xx=”123411”

    # echo ${#xx}

    6

    # xx=””

    # echo ${#xx}

    0

    脚本的交互式输出模式

    方法一:

    执行脚本过程中,存在需要用户输入内容的情况,通过read命令进行交互式输入

    添加注释给用户:

    输入格式:read -p “文本提示” 变量名

    0出格式:echo $变量名

     

    创建用户名和密码

    #!/bin/bash

    User="yunjisuan"

    Passwd="123456"

    read -p "请输入用户名" user

    read -p "请输入密码" passwd

    [ $User -eq $user ] && echo "YOU ARE RIGHT" || echo YOU ARE WRONG

    [ $Passwd -eq $user ] && echo "YOU ARE RIGHT" || echo "YOU ARE WRONG"

    逻辑测试

    []”中,-a&&) 表示并且;

    -o ||)表示或者

    !逻辑否

    方法二:通过参数传递的方式进行交互式输入

    /etc/init.d/ 服务启动脚本

    服务启动脚本/etc/init.d/后面写的内容就是参数,通过这个参数进行交互式输入

     

    $# 表示脚本要处理的的参数个数

    $? 表示命令或脚本执行状态码

    $* 表示横向罗列脚本要处理的所有参数(把所有参数视为整体)

    $@ 表示横向罗列脚本要处理的所有参数(把所有参数视为单个参数的组合)

    $0 表示脚本文件的绝对路径或相对路径(脚本文件的执行路径)

    $1 第一个参数

    $n n个参数

     

    脚本中反引号``”、“$()”的应用

     

    变量的算数运算

    变量的数值运算多用于脚本程序的过程控制,只能进行简单的整数运算,不支持小数运算,整数值得运算主要通过内部命令expr进行。

    # x=11

    # y=22

    # expr $x * $y

    格式: expr 变量1 运算符 变量2...

    ++ --   增加及减少,可前置也可放在结尾

     一元运算的正负号,非,逻辑与位的取反

    *   乘法

    /   除法

    %  取余

    **  幂运算

    + 加法

    -  减法

    <<=>>= 比较符号

    == 1+= 相等,不相等

    <<  向左移动

    >>  向右移动

    >>>  0右移

    & 位的与AND

    ^  位的异或

    |  位的或

    &&  位的AND

    ||   位的OR

    ?:  条件表达式

    =+= -= *=等 赋值运算符

    (())用法(常用于简单的整数运算)

    (())”在命令行执行时不需要$符号,但是输出需要$符号

    “(())”里所有字符之间有无或多个空格没有任何影响

    # b=$((1+2**3-4%3))

    # echo $b

    8

    # echo $((1+2**3-4%3))

    8

    a++a--,++a,--a区别

    变量a在前,表达式的值为a,然后a自增或自减,变量a在符号后,表达式值自增或自减,然后a值自增或自减。

    # a=8

    # echo $a

    8a赋值为8

    # echo $((a+=1)) #相当于a=a+1

    9a赋值为a+1=9

    # echo $((a++)) #a在前,先输出a的值,在加1

    9a赋值为上一值a9

    # echo $a

    10a赋值上一值的9++9+110

    # echo $((a--))

    10a取上一值a10

    # echo $a

    9a取上一值10--10-19

    # echo $((++a))

    10(先+1,在取上一值9,1+9=10

    # echo $a

    10(取上一值10

    # echo $((--a))

    9(先-1,取上一值1010-1=9

    # echo $a

    9(取上一值9

    Shell脚本中不支持“i++”表达,可以用C语言的((i++))shell中表示

    或者“let h++”

     

     

    If条件语句

    格式(fi 表示结束)

    (一)单分支条件判断语句

    1

    if    条件1

    then

    动作1

    else

    动作2

    fi

    2)(用;分隔)

    if 条件1;then

    动作1

    else

    动作2

    fi

    vim中编辑yunjisuan.sh脚本

    #!/bin/bash

    read -p "请输入一个数字:" num

    if [ $num == 60 ];then

    echo "猜对了"

    fi

    # sh yunjisuan.sh

    请输入一个数字:60

    猜对了

    vim中编辑yunjisuan.sh脚本

    #!/bin/bash

    read -p "请输入一个数字:" num

    if [ $num == 60 ];then

    echo "猜对了"

    else

    echo "猜错了"

    fi

    # sh yunjisuan.sh

    请输入一个数字:45

    猜错了

     

    (二)多分支条件判断语句(elif就是else if

     if 条件1;then

    动作1

    elif 条件2;then

    动作2

    else

    动作3

    fi

    查看当前文件的绝对目录

    # dirname 目标文件的绝对路径

    查看当前文件的基本文件名称

    # basename 目标文件的绝对路径

     

    自定义搭建本地yum仓库脚本

    (1)移除光盘,再挂载

    (2)判断光盘挂载

    (3)挂载本地yum仓库脚本

    (4)判断一级目录、二级目录是否存在

    (5)配置文件手动生成,避免之前被修改过(重定向或echo -e

    #!/bin/bash

    umount /dev/sr0&>/dev/null

    [ -d /media/cdrom ]|| mkdir -p /media/cdrom(还可以用testif的方法)

    mount /dev/sr0 /media/cdrom &>/dev/null

    if [ $? -ne 0 ];then

            echo "请插入光盘"

            exit

    fi

    [ -d /etc/yum.repos.d ] || mkdir -p /etc/yum.repos.d

    cd /etc/yum.repos.d

    mv * /tmp/  

    echo -e “[local] name=local baseurl=file:///media/cdrom/ gpgcheck=0 enabled=1”>/etc/

    yum.repos.d/localyum.repo

    (或)

    cat > /etc/yum.repos.d/localyum.repo << FOF

    [local]

    name=local

    baseurl=file:///media/cdrom

    gpgcheck=0

    enabled=1

    F0F

    yum -y clean all &>/dev/null

    yum makecache &>/dev/null

    [ $? -eq 0 ] && echo "yum仓库搭建完毕" || echo "缓存建立失败!"

    配置文件手动生成

    用脚本手动生成配置文件,一般用重定向

    输入重定向通过FOF标识(任意定义,但成对出现),将FOF之间的内容输入重定向到catcat再输出重定向给/etc/yum.repos.d/yum/repo文件

     

    while循环语句

    格式:

    while 条件

    do

    循环体(指令)

    done

    休息命令:sleep 1 休息1秒,usleep 1000000 休息1秒,单位微妙

    1100求和

    #!/bin/bash

    i=1

    sum=0

    while [ $i -lt 100 ]

    do

    ((sum=sum+i))

    ((i++))

    done

    echo $sum

    守护进程

    #!/bin/bash

    while true

    do

            uptime >> /var/log/uptime.log

            sleep 2

    done

    倒计时

    #!/bin/bash

    i=10

    while [ $i -gt 0 ]

    do

            echo $i

            ((i--))

    done

    无限循环

    1

    #!/bin/bash

    read -p "输入:" i

    while [ $i -gt 0 ]

    do

            echo $i

            let i++

    done

    2

    #!/bin/bash

    read -p "输入:" i

    while :

    do

            echo $i

            let i++

    done

    强行中止

    # exit

    防止脚本执行中断的方法

    1sh while01.sh & #放在后台执行
    2screen 分离 ctrl+a+d 查看screen -ls进入screen -r num
    3nohup while01.sh &

     

    for循环语句

    格式:

    for 变量名 in 变量取值列表

    do

    循环体(指令)

    done

    示例:循环

    for ((i=0;i<10:i++))

    do

    echo $i

    done

    打印列表元素

    for的三种输出方式

    1

    #!/bin/bash

    for i in 1 2 3 4 5

    do

            echo $i

    done

    (2)

    #!/bin/bash

    for i in {1..5}   

    do

            echo $i

    done

    (3)

    #!/bin/bash

    for i in `seq 5`

    do

            echo $i

    done

    #!/bin/bash

    h=0

    for i in {1..10}

    do

            echo $h

            let h++

    done

    开机启动项优化

    #!/bin/bash

    for i in `chkconfig | grep "3:on" | awk '{print $1}'`

    do

            chkconfig $i off

    done

    if [ -e sysstat ]

            then echo "sysstat exit"

            else mkdir -p /media/cdrom

            mount /dev/sr0 /media/cdrom

            if [ $? -ne 0 ];then

                    echo "FAILED"

                    exit

            else yum -y install sysstat

                    if [ $? -ne 0 ];then

                            echo "install error"

                            exit

                    else echo "install successed"

                    fi

            fi

    fi

    for h in sshd network crond rsyslog sysstat

    do

            chkconfig $h on

    done

    [ $? == 0 ]&& echo "successed" || echo "failed"

    /yunjisuan目录批量创建文件

    #!/bin/bash

    Path=/yunjisuan

    [ -d "$Path" ] || mkdir -p $Path

    for i in `seq 10`

    do

            touch $Path/yunjisuan_$i.html

    done

    批量改名

    #!/bin/bash

    Path=/yunjisuan

    [ -d "$Path" ] || mkdir -p $Path

    for file in `ls $Path`

    do

            mv $Path/$file "$Path/"`echo $file | sed -r 's#yunjisuan(.*).html#linux1.HTML#g'`

    done

    批量创建用户并设置密码

    #!/bin/bash

    User=yunjisuan

    Path=/tmp

    for user in ${User}{01..10}

    do

            useradd $user > /dev/null 2>&1

                    if [ $user -ne 0 ];then

                    echo "$user created failed"

                    echo "scripts begin to rollback"

                            for i in ${User}{01..10}

                            do

                                    userder -r $i >/dev/null 2>&1

                                    [ $? -eq 0 ] || exit 1

                            done

                    echo >$Path/usr_passwd

                    exit 1

                    else

                    passWD=`echo $RANDOM | md5sum | cut -c1-8` (表示取一大串随机数,从这串随机数前截取1-8位)

                    [ -d $Path ] || mkdir $Path

                    echo $passWD | passwd --stdin $user

                    echo "$user:$passWD">> $Path/user_passwd

                    fi

    done

     

    exit 0 表示正常运行程序并退出程序

    exit 1 exit -1 表示非正常运行导致退出程序

    echo -n 不换行

    获取当前目录下的目录名做为变量列表打印输出

    #!/bin/bash

    Path=`pwd`

    echo $Path

    for filename in `ls`

    do

            [ -d ${Path}/${filename} ] && echo $filename

    done

    九九乘法表

    #!/bin/bash

    for ((i=1;i<10;i++))

    do

            for ((j=1;j<=i;j++))

            do

                    echo -n "$j * $j =$((i*j))"

                    echo -n " "

            done

            echo " "

    done

    显示出1-100的偶数

    #!/bin/bash

    for i in {1..100}

    do

            [ $(($i%2)) -eq 0 ] && echo $i

    done

    显示出1000-2000的质数

    #!/bin/bash

    for i in {1000..2000}

    do

            [ $(factor $i | awk '{print NF}') -le 2 ] && echo $i

    done

     

    factor命令:分解因数

     

    Case语句

    用途:菜单;启动脚本

    case语句适合变量的值少,且为固定的数字或字符串集合。 系统服务启动脚本传参的判断多用case语句

    格式:

    case "字符串变量" in

        1

            指令1

            ;;

        2

            指令2

            ;;

        *)

            指令

    esac

    注意:case语句相当于一个if的多分支结构语句

    1的选项

    apple

        echo -e "@RED_COLOR apple $RES"

        ;;

    也可以这样写,输入2种格式找同一个选项

    apple|APPLE)

        echo -e "$RED_COLOR apple $RES"

        ;;

    服务脚本框架

    #!/bin/bash

    . /etc/init.d/functions

    case $1 in

            start)

                    action "服务开始启动"   /bin/true

                    ;;

            stop)

                    action "服务准备停止"   /bin/false

                    ;;

            restart)

                    action "服务准备停止"   /bin/true

                    action "服务来时启动"   /bin/true

                    ;;

            *)

                    echo "请输入正确参数"

                    ;;

    esac

    在当前脚本引用函数库(绝对路径)

    Function对应的是action “ ” 路径

    /bin/true 表示一个标志

      

     

    设置脚本配置启动级别

    (1)为脚本设置启动级别

    将脚本复制到/etc/init.d/下,vim编辑/etc/init.d/cash.sh脚本

    # chkconfig: 35 90 10

     

    (2)chkconfig中添加脚本

    # chkconfig --add case.sh

    # chkconfig --list case.sh

     

    (3)设置关闭cash.sh

    # chkconfig case.sh off

     

    Shell函数

    不论什么编程语言,基本只有三种编程的方法(指如何去编写代码的方法论)

    1、面向过程

    2、面向对象

    3、函数式编程

    shell语言中,只能支持面向过程这种编程方法。

    shell中,function表示函数(functionreturn可以不写)

    格式:

    function 函数名(){

    命令序列

    [return x]

    }

    函数名

     

    函数体只有被调用时才会启动,若要重复启动该函数,只需将函数名重复n

    获取随机数的几种方法

    (1)通过系统环境变量$RANDOM

    # echo $RANDOM

    6178

    # echo $RANDOM

    30890

    # echo $((RANDOM%9)) #输出09之间随机数

    2

    # echo $((RANDOM%9))

    # echo $((RANDOM%9))$((RANDOM%9)) #输出0099 随机数

    64

    # echo $RANDOM|md5sum #随机数长短不一,可以用md5sum命令统一格式化

    599e328a94329684ce5c92b850d32f26 -

    (2)通过openssl产生

    # openssl rand -base64 8

    aND8WMRM6vQ=

    # openssl rand -base64 8

    RsRdRq/9vi4=

    # openssl rand -base64 8|md5sum

    b1108cafbc2291392e41d2c914360138 -

    # openssl rand -base64 10

    1frkA2kIJODxqQ==

    (3)通过时间获得随机数(date命令详解见下页文档)

    # echo $(date +%N)

    361599138

    # echo $(date +%t%N)

    950526316

    (4)Urandom

    # head /dev/urandom | cksum

    621330951 2535

    # head /dev/urandom | cksum

    404398617 2470

    (5)UUID

    # cat /proc/sys/kernel/random/uuid

    8a6c5bbe-2d42-44ac-9ef1-3e7683a613e3

    # cat /proc/sys/kernel/random/uuid

    c828c209-5b5f-4bc7-917c-678ed4215988

    # uuidgen

    961dc354-81b2-4564-9b85-6095ed4bc7b5

    循环控制语句breakcontinueexitreturn

    作用:用于循环结构中控制循环语句

    break nn表示跳出循环的层数,如果省略n表示跳出整个循环(只跳出所在位置的循环)

    continue nn表示退出到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环剩余代码,进入循环的下一次循环exit n:退出当前shell程序,n为返回值,n也可以省略,在下一个shell里通过$?接收这个n

    return n用在函数里,做为函数的返回值,用于判断函数执行是否正确。和exit一样,如果函数里有循环,也会直接退出循环,退出函数

    break nn表示跳出循环的层数,如果省略n表示跳出整个循环

    #!/bin/bash

    for ((i=0;i<=5;i++))

    do

            [ $i -eq 3 ] && break

            echo $i

    done

    echo "ok"

    break只跳出所在位置的一个整个循环循环

     

    continue nn表示退出到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环剩余代码,进入循环的下一次循环

    #!/bin/bash

    for ((i=0;i<=5;i++))

    do

            [ $i -eq 3 ] && continue

            echo $i

    done

    echo "ok"

    exit n:退出当前shell程序,n为返回值,n也可以省略,在下一个shell里通过$?接收这个n

    #!/bin/bash

    for ((i=0;i<=5;i++))

    do

            [ $i -eq 3 ] && exit 2

            echo $i

    done

    echo "ok"

    return n:用在函数里,做为函数的返回值,用于判断函数执行是否正确。和exit一样,如果函数里有循环,也会直接退出循环,退出函数

    #!/bin/bash

    function xxx() {

            for ((i=0;i<=5;i++))

            do

                    [ $i -eq 3 ] && return 7

                            echo $i

            done

            echo "ok"

    }

    xxx

    echo $?

    shell脚本的调试

    (1)使用dos2unix处理脚本

    windows编辑的脚本到Linux下需要使用这个命令
    dos2unix windows.sh

    (2)使用echo命令调试

    在变量读取或修改的前后假如echo $变量,也可在后面使用exit退出脚本,这样可以不用注释后边代码

    3)利用bash的参数调试

    sh [-nvx]
    -n:不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示。可用于生产服务器那些只能执行一次不可逆的脚本。
    -v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示。(一般不用)
    -x:将执行的脚本内容及输出显示到屏幕上,常用

    1)要记得首先用dos2unix对脚本格式化
    2)直接执行脚本根据报错来调试,有时报错不准确。
    3sh -x调试整个脚本,显示执行过程。
    4set -xset +x调试部分脚本(在脚本中设置)
    5echo输出变量及相关内容,然后紧跟着exit退出,不执行后面程序的方式,一步步跟踪脚本,对于逻辑错误比较好用。

    ping -c 1 ip   ping一次

    #!/bin/bash

    for ip in 192.168.214.{1..254}

    do

            ping -c 1 $ip &> /dev/null

            if [$? -eq 0 ];then

                    echo "$ip正常状态"

            fi

    done

     

  • 相关阅读:
    [NOIP2018-普及组] 对称二叉树
    UVA1637 【纸牌游戏 Double Patience】
    [SHOI2002]滑雪-题解
    题解 CF1437E 【Make It Increasing】
    题解 P4331 【[BalticOI 2004]Sequence 数字序列】
    NOIp 2020游记
    题解 P3825 【[NOI2017]游戏】
    题解 P6453 【[LNOI2014]LCA】
    题解 P6453 【[COCI2008-2009#4] F】
    题解 P5779 【[CTSC2001]聪明的学生】
  • 原文地址:https://www.cnblogs.com/daisy118/p/9886534.html
Copyright © 2011-2022 走看看