当前位置 博文首页 > 曹世宏的博客:Linux下的shell脚本

    曹世宏的博客:Linux下的shell脚本

    作者:[db:作者] 时间:2021-09-12 18:11

    shell脚本的基本结构:

    shell脚本示例:

    [root@localhost ~]# cd /usr/local/sbin/
    [root@localhost sbin]# vim first.sh
    #! /bin/bash
    
    ## This is my first shell script.
    ## Writen by Cao 2018-7-2.
    
    date
    echo "Hello world!"

    shell脚本用注意事项:

    Shell脚本通常都是以.sh 为后缀名的**,这个并不是说不带.sh这个脚本就不能执行,只是大家的一个习惯而已。所以,遇见.sh结尾的文件通常都是脚本。

    shell脚本中第一行要以 “#! /bin/bash” 开头,它代表的意思是,该文件使用的是bash语法。如果不设置该行,虽然shell脚本也可以执行,但是这不符合规范。

    # 表示注释。后面跟一些该脚本的相关注释内容以及作者和创建日期或者版本等等。为了方便管理,写注释是非常必要的。

    shell脚本执行方法:

    1. sh shell.sh

      另外使用sh命令去执行一个shell脚本的时候是可以加-x选项来查看这个脚本执行过程的,这样有利于我们调试这个脚本哪里出了问题:

    2. ./first.sh 该方法通常需要更改文件权限。chomod +x shell.sh

    [root@localhost sbin]# sh -x first.sh 
    + date
    20180702日 星期一 15:05:17 CST
    + echo 'Hello word!'
    Hello word!

    命令date:

    [root@localhost sbin]# date +"%Y-%m-%d %H:%M:%S"
    2018-07-02 15:08:01
    [root@localhost sbin]# date
    2018年 07月 02日 星期一 15:08:04 CST

    date在脚本中最常用的几个用法:

    data +%Y 以四位数字格式打印年份

    date +%y 以两位数字格式打印年份

    date +%m 月份

    date +%d 日期

    date +%H 小时

    date +%M 分钟

    date +%S

    date +%w 星期,如果结果显示0 则表示周日

    有时在脚本中会用到一天前的日期:

    [root@localhost sbin]# date -d "-1 day" +%d
    23

    或者一小时前:

    [root@localhost sbin]# date -d "-1 hour" +%H
    18

    甚至1分钟前:

    [root@localhost sbin]# date -d "-1 min" +%M
    50

    shell脚本中的变量:

    变量就是和其他编程语言中的变量一样,为了简化和使代码更容易维护。

    使用变量的脚本示例:

    [root@localhost sbin]# cat variable.sh 
    #! /bin/bash
    
    ## In this script we will use variables.
    ## Writen by Cao 2018-7-2.
    
    d=`date +%H:%M:%S`
    echo "The script begin at $d"
    echo "Now we'll sleep 2 seconds."
    sleep 2
    d1=`date +%H:%M:%S`
    echo "The script end at $d1."
    [root@localhost sbin]# ./variable.sh 
    The script begin at 15:21:23
    Now we'll sleep 2 seconds.
    The script end at 15:21:25.

    脚本中使用了反引号 ” ` ” , 反引号的作用:在Linux中起着命令替换的作用。命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置。

    d’ 和 ‘d1’ 在脚本中作为变量出现,定义变量的格式为 变量名=变量的值
    当在脚本中引用变量时需要加上 ‘$’ 符号,引用变量的符号。

    使用shell计算两个数的和:

    [root@localhost sbin]# cat sum.sh 
    #! /bin/bash
    
    ## For get the sum fo tow numbers.
    ## Cao 2018-7-2.
    
    a=1
    b=2
    sum=$[$a+$b]
    #数学计算要用[ ]括起来并且外头要带一个 ‘$’ 
    
    echo "$a+$b=$sum"
    [root@localhost sbin]# ./sum.sh 
    1+2=3

    Shell脚本还可以和用户交互:

    [root@localhost sbin]# cat read.sh 
    #! /bin/bash
    
    ## Using 'read' in shell script.
    ## Writen by Cao 2018-7-2.
    
    read -p "Please input a number:" x
    read -p "please input another number:" y
    sum=$[$x+$y]
    echo "The sum of the tow number is:$sum"
    
    [root@localhost sbin]# sh read.sh 
    Please input a number:20
    please input another number:30
    The sum of the tow number is:50

    shell的预设变量:

    shell中的预设变量$0,代表脚本本身的名字。

    shell脚本的逻辑判断:

    在shell中的判断的基本语法为:

    if  判断语句一  ; then
        command
    elif  判断语句二; then
        command
    else
        command
    fi

    使用示例:

    [root@localhost sbin]# cat if.sh 
    #! /bin/bash
    
    read -p "Please input your score:" a
    if ((a<60)); then
            echo "You didn't pass the exam"
    elif ((a>=60)) && ((a<85)); then
            echo "Good! You pass the exam."
    else
            echo "very good! Your socre is very high!"
    fi
    [root@localhost sbin]# sh if.sh 
    Please input your score:90
    very good! Your socre is very high!
    [root@localhost sbin]# sh if.sh 
    Please input your score:78
    Good! You pass the exam.
    [root@localhost sbin]# sh if.sh 
    Please input your score:49
    You didn't pass the exam

    在判断数值大小除了可以用 (( )) 的形式外,还可以使用 [ ] 但是就不能使用>, < , = 这样的符号了,要使用 -lt (小于),-gt (大于),-le (小于等于),-ge (大于等于),-eq (等于),-ne (不等于)。

    [root@localhost sbin]# a=10; if [ $a -lt 5 ]; then echo ok; fi
    [root@localhost sbin]# a=10; if [ $a -gt 5 ]; then echo ok; fi
    ok
    [root@localhost sbin]# a=10; if [ $a -ge 10 ]; then echo ok; fi
    ok
    [root@localhost sbin]# a=10; if [ $a -eq 10 ]; then echo ok; fi
    ok
    [root@localhost sbin]# a=10; if [ $a -ne 10 ]; then echo ok; fi

    shell 脚本中if还经常判断关于档案属性,比如判断是普通文件还是目录,判断文件是否有读写执行权限等。常用的也就几个选项:

    -e :判断文件或目录是否存在

    -d :判断是不是目录,并是否存在

    -f :判断是否是普通文件,并存在

    -r :判断文档是否有读权限

    -w :判断是否有写权限

    -x :判断是否可执行

    使用if判断时,具体格式为:

    if [ -e filename ] ; then

    root@localhost sbin]# if [ -f /root/test.txt ]; then echo ok; fi
    ok
    [root@localhost sbin]# if [ -r /root/test.txt ]; then echo ok; fi
    ok
    [root@localhost sbin]# if [ -w /root/test.txt ]; then echo ok; fi
    ok
    [root@localhost sbin]# if [ -x /root/test.txt ]; then echo ok; fi
    [root@localhost sbin]# if [ -e /root/test1.txt ]; then echo ok; fi

    case的使用方法:

    case  变量  in
    value1)
              command
              ;;
    value2)
              command
              ;;
    value3)
              command
              ;;
    *)
              command
              ;;
    esac

    面的结构中,不限制value的个数, * 则代表除了上面的value外的其他值。

    判断输入数值是奇数或者偶数的脚本:

    [root@localhost sbin]# cat case.sh 
    #! /bin/bash
    
    read -p "Input a number:" n
    a=$[$n%2]
    case $a in
        1)
            echo "The number is odd."
            ;;
        0)
            echo "The number is even."
            ;;
        *)
            echo "It's not a number!"
            ;;
    esac
    [root@localhost sbin]# sh case.sh 
    Input a number:79
    The number is odd.
    [root@localhost sbin]# sh case.sh 
    Input a number:90
    The number is even.
    [root@localhost sbin]# sh case.sh 
    Input a number:sd
    The number is even.

    case脚本常用于编写系统服务的启动脚本,例如/etc/init.d/iptables中就用到了。

    shell脚本中的循环:

    for循环的基本结构:

    for 变量名 in 循环的条件; do
         command
    done

    for循环示例:

    [root@localhost sbin]# cat for.sh 
    #! /bin/bash
    
    #脚本中的 seq 1 5 表示从15的一个序列。
    for i in `seq 1 5`; do
            echo $i
    done
    [root@localhost sbin]# sh for.sh 
    1
    2
    3
    4
    5
    [root@localhost sbin]# for i in 1 2 3 a b; do echo $i; done
    1
    2
    3
    a
    b

    while循环:

    while  条件; do
    
              command
    done

    while使用示例:

    [hadoop@localhost ~]$ cat while.sh 
    #! /bin/bash
    
    a=5
    while [ $a -ge 1 ]; do
            echo $a
            a=$[$a-1]
    done
    [hadoop@localhost ~]$ sh while.sh 
    5
    4
    3
    2
    1
    [hadoop@localhost ~]$ 

    另外可以把循环条件拿一个冒号替代,这样可以做到死循环。

    shell脚本中的函数:

    在shell脚本函数的格式为:

    function 函数名() {
    
    command
    
    }

    在shell脚本中,函数一定要写在最前面,不能出现在中间或者最后,因为函数是要被调用的,如果还没有出现就被调用,肯定是会出错的。

    函数使用示例:

    [root@localhost sbin]# cat func.sh 
    #! /bin/bash
    
    function sum()
    {
        sum=$[$1+$2]
        echo $sum
    }
    
    sum $1 $2
    [root@localhost sbin]# sh func.sh 1 2
    3
    [root@localhost sbin]# sh func.sh 4 5
    9

    shell脚本实例:

    (1)计算1-100的和:

    [root@localhost sbin]# cat sum1-100.sh 
    #! /bin/bash
    
    ## Sum(1-100)
    sum=0
    for i in `seq 1 100`; do
        sum=$[$i+$sum]
    done
    
    echo $sum
    [root@localhost sbin]# sh sum1-100.sh 
    5050

    (2)要求输入一个数字,然后计算出从1到输入数字的和,要求,如果输入的数字小于1,则重新输入,直到输入正确的数字为止;

    [root@localhost sbin]# cat sum.sh 
    #! /bin/bash
    
    n=0
    while [ $n -lt "1" ]; do
            read -p "Please input a number, it must greater than "1":" n
    done
    
    sum=0
    
    for i in `seq 1 $n`; do
            sum=$[$i+$sum]
    done
    
    echo $sum
    [root@localhost sbin]# sh sum.sh 
    Please input a number, it must greater than 1:50
    1275
    [root@localhost sbin]# 

    (3)把/root/目录下的所有目录(只需要一级)拷贝到/tmp/目录下;

    [root@localhost sbin]# cat copydir.sh 
    #!/bin/bash
    
    cd /root
    for f in `ls`; do
            if [ -d $f ] ; then
                    cp -r $f /tmp
            fi
    done
    [root@localhost sbin]# sh copydir.sh 
    [root@localhost sbin]# ls /tmp
    Desktop
    Documents
    Downloads
    Music
    Pictures
    Public

    (4)批量建立用户user_00, user_01, … user_100并且所有用户同属于users组;

    [root@localhost sbin]# cat useradd.sh 
    #! /bin/bash
    
    groupadd users
    
    for i in `seq 0 9`; do
            useradd -g users user_0$i
    done
    
    for j in `seq 10 100`; do
            useradd -g users user_$j
    done
    [root@localhost sbin]# sh useradd.sh 
    [root@localhost sbin]# cat /etc/passwd | grep user
    user_00:x:1005:100::/home/user_00:/bin/bash
    user_01:x:1006:100::/home/user_01:/bin/bash
    user_02:x:1007:100::/home/user_02:/bin/bash
    user_03:x:1008:100::/home/user_03:/bin/bash
    user_04:x:1009:100::/home/user_04:/bin/bash
    user_05:x:1010:100::/home/user_05:/bin/bash
    user_06:x:1011:100::/home/user_06:/bin/bash

    (5)截取文件test.log中包含关键词 ‘abc’ 的行中的第一列(假设分隔符为 ”:” ),然后把截取的数字排序(假设第一列为数字),然后打印出重复次数超过10次的列;

    #! /bin/bash
    
    awk -F':' '$0~/abc/ {print $1}' test.log >/tmp/n.txt
    sort -n n.txt |uniq -c |sort -n >/tmp/n2.txt
    awk '$1>10 {print $2}' /tmp/n2.txt

    (6)判断输入的IP是否正确(IP的规则是,n1.n2.n3.n4,其中1

     #! /bin/bash
    
    checkip() {
    
            if echo $1 |egrep -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' ; then
                    a=`echo $1 | awk -F. '{print $1}'`
                    b=`echo $1 | awk -F. '{print $2}'`
                    c=`echo $1 | awk -F. '{print $3}'`
                    d=`echo $1 | awk -F. '{print $4}'`
    
                    for n in $a $b $c $d; do
                            if [ $n -ge 255 ] || [ $n -le 0 ]; then
                                    echo "the number of the IP should less than 255 and greate than 0"
                                    return 2
                            fi
                    done
            else
    
                    echo "The IP you input is something wrong, the format is like 192.168.100.1"
                    return 1
            fi
    
    }
    
    rs=1
    while [ $rs -gt 0 ];