# shell基础

1-7、1-8 本地变量

全局变量:家目录的.bash_profile、/etc/profile
环境变量一般都大写;应用于进程前,必须用export命令导出方能生效
//定义环境变量(通常放在/etc/profile中)
# export 变量名=value
# 变量名=value; export 变量名
# declare -x 变量名=value
//取消环境变量
# unset 变量名
//定义局部变量
# 变量名=value
# 变量名='value'
# 变量名="value"
-- 第一种定义为直接定义变量内容,一般定义简单连续的数字、字符串、路径名等
-- 第二种通过单引号定义变量,特点:输出变量时引号里是什么就输出什么,即使有变量也会原样输出,一般定义纯字符串
-- 第三种通过双引号定义变量,特点:输出变量时引号里的变量经过解析后输出变量内容,一般定义带有变量内容的字符串
# 习惯:数字不加引号,其他默认加双引号
# 特殊例子:awk单引号解析双引号不解析
  $ ETT=123
  $ awk 'BEGIN{print '$ETT'}'
  $ 123
  $ awk 'BEGIN{print "$ETT"}'
  $ ett
//全局变量和局部变量命名
-- 脚本中全局变量定义,在变量使用时,使用{}将变量括起来,示例:
   VERSION="2.2.22"
   SOFTWARE_NAME="httpd"
   SOFTWARE_FULLNAME="${SOFTWARE_NAME}-${VERSION}.tar.gz"
-- 脚本函数中的局部变量,要以local方式进行声明,使之只在本函数域内有效防止变量在函数中命名与外部程序重名造成异常.示例:
   function TestFunc()
   {
       #local声明i
       local i             
       for((i=0;i<n;i++))
       do
       echo 'do something'
       done
   }
//命令定义变量
# 变量名=`命令`
# 变量名=$(命令)
-- 示例1:
   # cmd=`date +%F`
   # echo $cmd
   2020-01-30
-- 示例2:
   # cmd=$(date +%F)
   # echo $cmd
   2020-01-30
-- 注:
   ${WEEK}day,若变量和其他字符组成新的变量就必须给变量加上大括号
-- 注:
   养成在所有字符串变量用双引号括起来的习惯,将会减少很多错误。具体如"$A"或"${A}"

1-9、1-10、1-11特殊变量

//位置变量
# 获取当前执行shell脚本的文件名(包括路径): $0
  -- 示例:
     # vim 0.sh
     echo $0
     # sh 0.sh
     0.sh
     # sh /root/0.sh
     /root/0.sh
   -- 实战:
     # vim 0.sh
     dirname $0
     basename $0
     # sh /root/0.sh
     /root
     0.sh
# 获取当前执行的shell脚本第n个参数值,如果n大于9,需用${}表示,例如${10}:$n
  -- 示例:
     # vim n.sh
     echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}
     # sh n.sh aa bb
     aa bb
     # sh n.sh `seq -s " " 10`
     1 2 3 4 5 6 7 8 9 10
# 获取参数个数:$#
  -- 示例:
     # vim n.sh
     echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}
     echo $#
     # sh n.sh aa bb
     aa bb
     2
     # sh n.sh "1 2 3 4 5"
     1 2 3 4 5
     1
//进程状态变量
# 获取上一个指令的返回值(0为成功,非0为失败):$?
  -- 常见返回值说明:
     2     :权限限制
     126   :找到了该命令,但无法执行
     1~125 :运行失败,脚本命令、系统命令错误或参数传递错误
     127   :未找到要运行的命令
     >128  :命令呗系统强制结束
# 获取当前shell的进程号(PID): $$
# 获取执行命令或脚本最后一个参数:$_
# 获取当前shell所有参数,所有参数视为单个字符串:$*
# 获取当前shell所有参数,每个参数视为单个字符串:$@

1-12 bash内部变量

//内部命令:
  -- 用的较多的:echo,export,read,exit
  -- 用的较少的:eval,exec,shift,点(.)
  -- 几乎不用的:wait
//shift语句:程序中每使用一次shift语句,都使所有的位置参数依次向前移动一个位置,并使位置参数$#减1,直到减到0为止
-- 示例:
   # set -- "I am" handsome man
   # echo $#
   3
   # echo $1
   I am
   # echo $2
   handsome
   # shift
   # echo $#
   2
   # echo $1
   handsome
   # echo $2
   man

1-13 变量字串应用

${#string}     //返回$string的长度
   -- 示例:
      # OLDBOY="I am oldboy"
      # echo $OLDBOY
      I am oldboy
      # echo ${#OLDBOY}
      11
${string:position}  //position为数字,假设为2,从第3个字符串截取到截取
   -- 示例:
      # OLDBOY="I am oldboy"
      # echo ${OLDBOY:2}
      am oldboy
${string:position:length}  //从position之后截取长度为length的子串
    -- 示例:
      # OLDBOY="I am oldboy"
      # echo ${OLDBOY:2:2}
      am
${string/substring/replace}  //使用$replace,代替第一个匹配的$substring
${string//substring/replace}  //使用$replace,代替所有匹配的$substring

1-14 实践

  1. 批量改名

    # ls
    stu_102999_1_finished.jpg
    stu_102999_2_finished.jpg
    stu_102999_3_finished.jpg
    stu_102999_4_finished.jpg
    test.sh
    # cat test.sh
    #!/bin/bash
    for i in `ls *.jpg`
    do
       mv $i `echo ${i/finished/}`
    done
    # sh test.sh
    # ls
    stu_102999_1_.jpg
    stu_102999_2_.jpg
    stu_102999_3_.jpg
    stu_102999_4_.jpg
    
    # ls
    stu_102999_1_finished.jpg
    stu_102999_2_finished.jpg
    stu_102999_3_finished.jpg
    stu_102999_4_finished.jpg
    # rename "finished" "" *.jpg
    stu_102999_1_.jpg
    stu_102999_2_.jpg
    stu_102999_3_.jpg
    stu_102999_4_.jpg
    
    # ls
    stu_102999_1_finished.jpg
    stu_102999_2_finished.jpg
    stu_102999_3_finished.jpg
    stu_102999_4_finished.jpg
    # ls *.jpg | awk -F 'finished' '{print "mv "$0" "$1$2}' | bash
    # ls *.jpg
    stu_102999_1_.jpg
    stu_102999_2_.jpg
    stu_102999_3_.jpg
    stu_102999_4_.jpg
    

1-15 变量替换

  1. $

    -- 如果变量名存在且非空,则返回变量值。否则返回字符串。

    -- 生产环境用来判断变量是否定义

    # result=${test:-UNSET}
    # echo $result
    UNSET
    # echo $test
    
    
  2. $

    -- 如果变量名存在且非空,则返回变量值。否则,设置这个变量值为word,并返回其值

    -- 用途:如果变量未定义,则设置变量值未默认值,并返回默认值

    # result=${test:=UNSET}
    # echo $result
    UNSET
    # echo $test
    UNSET
    
  3. $

    -- 如果变量名存在且非空,则返回变量值。否则显示变量名:message,并退出当前的命令或脚本

    -- 用途:用于捕捉由于变量未定义而导致的错误,并退出程序

    -- 范例:${value:?"not defined"}如果value未定义,则显示-bash: value:not defined并退出

  4. -- 如果变量名存在且非空,则返回word。否则返回空。

    -- 用途:测试变量是否存在

  5. -- 如果变量没定义,用-后面的word定义

2-1 变量处理耗时对比

  1. 获取字符串长度三种方法

    # chars=`seq -s " " 100`
    # echo ${#chars}
    291
    # echo $chars| wc -m
    291
    # echo $(expr length "$chars")
    291
    
  2. 测试执行效率

    # chars=`seq -s " " 100`
    # time for i in $(seq 11111);do count=${#chars};done
    real 0m0.723s
    user 0m0.706s
    sys  0m0.010s
    

    -- 执行11111次for循环,做变量定义,查看执行时间

    -- 在1中,第一种方法耗时最短

    -- 结论:在shell编程中,应尽量用内置操作或函数完成

  3. 变量详细说明博客

    https://www.cnblogs.com/chengmo/archive/2010/10/02/1841355.html
    

2-2 2-4变量的数值计算

  1. (()) #此法很常用,且效率高,仅支持整数运算

    -- 用于执行简单的整数运算,只需将特定的算术表达式用"$(("和"))"括起

    -- shell的算数运算符号常置于"$(("……"))"的语法中。这一语法如同双引号功能,除了内嵌双引号无需转义。

    * / %          //乘法、除法、取余
    + -            //加法、减法
    < <= > >=      //比较符号
    == !=         //相等与不等
    &&             //逻辑的AND
    ||             //逻辑的OR
    ?:             //条件表达式
    

    -- 示例1:

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

    -- 示例2:

    # a=$((a=1+2**3-4%3))
    # echo $((a+=1))
    9
    # echo $((a++))
    9
    # echo $a
    10
    # echo $((a--))
    10
    # echo $a
    9
    # echo $((++a))
    10
    # echo $a
    10
    # echo $((--a))
    9
    # echo $a
    9
    # echo $((3>2))
    1                  //变量为真返回1
    # echo $((3>8))
    0                  //变量为假返回0
    

    结论:变量在前,先输出变量值,变量在后,就是先运算后输出变量的值。

    --示例3:

    # myvar=99
    # myvar=$(($myvar+1))
    # echo $myvar
    100
    # echo $((myvar/5))
    20
    # echo $((myvar*5))
    500
    # echo $((myvar**5))
    100000000000
    # echo $((myvar%5))
    0
    

    -- 示例4:通过命令行传参,实现a、b两个变量混合运算

    # cat > test.sh
    #!/bin/bash
    a=$1
    b=$2
    echo "a-b=$(($a - $b))"
    echo "a+b=$(($a + $b))"
    echo "a*b=$(($a * $b))"
    echo "a/b=$(($a / $b))"
    echo "a**b=$(($a ** $b))"
    echo "a%b=$(($a % $b))"
    # sh test.sh 6 2
    a-b=4
    a+b=8
    a*b=12
    a/b=3
    a**b=36
    a%b=0
    

    -- 实践:设计一个四则运算计算器,要求有数字提示、有运算符提示。

  2. $[]

    # echo $[2 + 3]
    5
    # echo $[2 * 3]
    6
    

2-5 let

  1. 格式:let 赋值表达式,等同于((赋值表达式))

    # i=2
    # let i=i+8
    # echo i
    10
    

    结论:let i=i+8等同于((i=i+8)),但后者效率更高,生产环境一般不用let

2-6 expr

  1. expr一般用于整数,也可用于字符串,用来求表达式变量的值

    语法:expr [expression]

    注:expr后面的运算中,运算符需要两侧需要有空格;*需要转译

    # expr 2 + 3
    5
    # expr 2+3
    2+3
    # expr 2 * 2
    expr:语法错误
    # expr 2 \* 2
    4
    # expr $[2+3]
    5
    # expr $[2*3]
    6
    
  2. expr判断扩展名

    # expr "abc.pub" : ".*\.pub"
    0
    # expr "abc.txt" : ".*\.pub"
    8
    

    结论:匹配*pub文件,如果匹配,返回字符串的长度(非0),如果不匹配,返回0

    # expr "text.pub" : ".*\.pub" && echo 1 || echo 0
    8
    1
    # expr "text.x" : ".*\.pub" && echo 1 || echo 0
    0
    0
    

    说明:与*.pub进行匹配,如果匹配成功,返回1,否则返回0

  3. expr判断是否为整数

    # cat > test.sh
    #!/bin/bash
    read -p "Pls input :" a
    expr $a + 0 >/dev/null 2>&1
    [ $? -eq 0 ] && echo int || echo chars
    # sh test.sh
    Pls input :2
    int
    # sh test.sh
    Pls input :aaa
    chars
    

2-7 bc

  1. 简单用法

    # i=2
    # n=3.5
    # echo $i+1
    2+1
    # echo $i+1 | bc
    3
    # echo $n+1.2
    3.5+1.2
    # echo $n+1.2 | bc
    4.7
    # seq -s "+" 10 | bc
    55
    

    总结:bc的特点支持小数运算;只要正确的运算表达式都可以通过管道交给bc处理

  2. 取百分比

    # echo "scale=2;234 / 543 * 100" | bc | awk -F '.' '{print $1"%"}'
    43%
    

2-8 read

  1. 语法:

    ​ read [参数] [变量名]

  2. 常用参数

    ​ -p string:设置提示信息

    ​ -t timeout:设置输入等待的时间,单位默认为秒

  3. 示例

    # read -p "pls one insert:" a1
    pls insert: test
    # echo ${a1}
    test
    # read -p "pls two insert:" a1 a2
    pls two insert:11 22
    # echo ${a1} ${a2}
    11 22
    

    如果读入不是整数,以上脚本会报错。

    如何解决?

    cat > test2.sh
    #!/bin/bash
    while true
    do
      read -t 10 -p "pls input two number:" a b
      expr $a + 0 >/dev/null 2>&1
      [ $? -ne 0 ] && continue
      expr $b + 0 >/dev/null 2>&1
      [ $? -ne 0 ] && continue || break
    done
    echo "a-b =$(( $a - $b))"
    echo "a+b =$(( $a + $b))"
    

    总结:continue为终止当前循环,执行下一次循环;break为跳出当前循环,执行循环外面的内容。

    如果读入参数不是两个,以上脚本会报错。

    如何解决?

    cat > test2.sh
    #!/bin/bash
    a="$1"
    b="$2"
    Usage(){
        echo "Usage:sh $0 num1 num2"
        exit
    }
    if [ $# -ne 2 ];then
        Usage
    fi
    expr $a + 0 >/dev/null 2>&1
    [ $? -ne 0 ] && Usage
    expr $b + 0 >/dev/null 2>&1
    [ $? -ne 0 ] && Usage
    echo "a-b =$(( $a - $b))"
    echo "a+b =$(( $a + $b))"
    

2-9 条件测试

  1. 语法:

    • 格式1:test <测试表达式>
    • 格式2:[ <测试表达式> ]
    • 格式3:[[ <测试表达式> ]]

    说明:格式1和格式2等价的,生产环境推荐格式2。格式3是test命令的拓展,在[[]]可以使用通配符进行模式匹配,&&、||、>、<等操作符可用于[[]]中,但不能用于[]中。

    -- test测试文件是否存在

    # test -f file && echo 1 || echo 0
    0
    

    ​ 注: -f:文件存在且为普通文件为真

    ​ -d:文件存在且为普通文件为真

    ​ -s:文件存在且不为空为真(size非0)

    ​ -e:文件存在为真

    ​ f1 -nt f2:文件f1比文件f2新为真

    ​ f1 -ot f2:文件f1比文件f2旧为真

    -- []用法,!为非的操作

    # [ -f file ] && echo 1 || echo 0
    0
    # [ ! -f file ] && echo 1 || echo 0
    1
    

    -- [[]]用法

    # [[ -f file ]] && echo 1 || echo 0
    0
    # [[ ! -f file ]] && echo 1 || echo 0
    1
    # [[ -f file && -d folder ]] && echo 1 || echo 0
    0
    # [ -f file && -d folder ] && echo 1 || echo 0
    -bash: [: missing `]'
    0
    # [ -f file -a -d folder ] && echo 1 || echo 0
    0
    

2-10 字符串、整数测试操作符

  1. 字符串常见操作符

    用法 说明
    -z "字符串" 字符串长度为0则真,可以理解为zero,如:[ -z "$myvar" ]
    -n "字符串" 字符串长度非0则真,可以理解为no zero,如:[ -n "$myvar" ]
    "串1"="串2" 串1等于串2为真,可用==代替=
    "串1"!="串2" 串1不等于串2为真
  2. 整数常见操作符

    在[]中使用的比较符 在(())或[[]]中使用的比较符 说明
    -eq == equal的缩写,相等
    -ne != not equal的缩写,不相等
    -gt > 大于 greater than
    -ge >= 大于等于 greater equal
    -lt < 小于 less than
    -le <= 小于等于 less equal

    -- 示例:

    # [ 2 -gt 1 ] && echo 1 || echo 0
    1
    # [ 2 -lt 1 ] && echo 1 || echo 0
    0
    # [[ 2 > 1 ]] && echo 1 || echo 0
    1
    # [[ 2 < 1 ]] && echo 1 || echo 0
    0
    

2-11 逻辑操作符与文件条件测试

  1. 逻辑操作符

    在[]中使用 在[[]]中使用 说明
    -a &&
    -o ||
    ! !
  2. 条件测试举例

    # file1=/etc/services;file2=/etc/rc.local
    # echo $file1 $file2
    /etc/services /etc/rc.local
    # [ -f "$file1" ] && echo 1 || echo 0
    1
    # [ -d "$file1" ] && echo 1 || echo 0
    0
    # [ -e "$file1" ] && echo 1 || echo 0
    1
    # [ -s "$file1" ] && echo 1 || echo 0
    1
    # dir1=/etc
    # [ -d "$dir1" ] && echo 1 || echo 0
    1
    

2-12 文件字符串多操作符实践

  1. 示例1:复习

    # echo $file1 $file2
    /etc/services /etc/rc.local
    # [ -f "$file1" -a -e "$file2" ] && echo 1 || echo 0
    1
    # [ -f "$file1" -o -e "$file2" ] && echo 1 || echo 0                   
    1
    # [ -f "$file1" || -e "$file2" ] && echo 1 || echo 0
    -bash: [: missing `]'
    -bash: -e: command not found
    0
    # [[ -f "$file1" || -e "$file2" ]] && echo 1 || echo 0
    1
    
  2. 示例2:测试判断写一半

    # [ -f "$file1" ] && echo 1    //条件成立返回1,不成立不管
    1
    # [ -f "$file10" ] || echo 0   //条件不成立返回0,成立不管
    0
    
  3. 示例3:判断后多命令执行

    [ 判断 ] || { 命令1 ; 命令2 ; 命令3 }
    

    等同于:

    if [判断];then
        do someting
    else
        命令1
        命令2
        命令3
    fi
    

2-13 字符串测试举例

  1. 示例:复习

    # echo $file1 $file2
    
    # [ -n "$file1" ] && echo 1 || echo 0
    0
    # [ -z "$file1" ] && echo 1 || echo 0
    1
    # [ -z "$file1" -a -n "$file" ] && echo 1 || echo 0
    0
    

    注:字符串比较,变量一定要加""

  2. 示例:比较字符串长度

    # file1=/etc/services
    # file2=/etc/rc.local
    # [ "${#file1}" = "${#file2}" ] && echo 1 || echo 0
    1
    

2-16 cat应用

  1. 示例:利用cat打印选择菜单

    # cat menu.sh
    menu(){
    cat << END
    1.[apple]
    2.[pear]
    3.[banana]
    4.[cherry]
    5.[orange]
    please select one that you like:
    END
    }
    menu
    read a
    echo "you selected $a"
    # sh menu.sh
    1.[apple]
    2.[pear]
    3.[banana]
    4.[cherry]
    5.[orange]
    please select one that you like:
    1
    you selected 1
    

2-17~19 if分支语句

  1. 示例:比较两个整数大小

    # cat > test4.sh
    #!/bin/bash
    read -p "Pls input two num: " a b
    if [ $a -eq $b ]
    then
        echo "$a等于$b"
    elif [ $a -gt $b ]
    then
        echo "$a大于$b"
    else
        echo "$a小于$b"
    fi
    
  2. 示例:实现如果/server/scripts下面存在if3.sh,就打印if3.sh,否则创建if3.sh

    # cat > test6.sh
    #!/bin/bash
    file="/server/scripts/if3.sh"
    if [ -f ${file} ] ;then
        echo "${file} is exsit"
        else
            touch ${file}
            echo "${file} is touched"
    fi
    

    注: sh -x test6.sh //显示执行过程,用于调试

  3. 判断是否输入为整数

    -- 方法1:sed替换数字

    # [ -z "`echo 2222|sed 's/[0-9]//g'`" ] && echo 1 || echo 0
    1
    # [ -z "`echo 2222kkk|sed 's/[0-9]//g'`" ] && echo 1 || echo 0
    0
    

    -- 方法2:expr

    # expr $1 + 0 >/dev/null 2>&1
    # [ $? -eq 0 ] && echo int
    

    --方法3:正则表达式,去掉非数字部分与原变量比较

    # b=1a2b3c
    # [ -n "$b" -a "$b" = "${b//[^0-9]/}" ] && echo int || echo chars
    chars
    

3-2 3-3生产环境监控mysql服务

  1. 监控mysql服务是否存在,如果不存在,启动mysql

    # cat > aaa.sh
    #!/bin/bash
    PORT=`netstat -lnt | grep 3306 | awk -F '[ :]+' '{print $5}'`
    if [ "$PORT" != "3306" ];then
        service mysqld start
    else
        echo "db is running"
    fi
    

3-7 case

  1. 语法:

    case "字符变量" in
       值1) 指令…
    ;;
       值2) 指令…
    ;;
       *) 指令…
    esac
    
  2. 示例1: 数字输入

    # cat case_1.sh
    read -p "Pls input a number:" ans
    case "$ans" in
    1)
        echo "the num you input is 1"
    ;;
    2)
        echo "the num you input is 2"
    ;;
    [3-9])
        echo "the num you input is $ans"
    ;;
    *)
        echo "the num you input must be less than 9"
        exit
    ;;
    esac
    
  3. 示例2: 模糊匹配

    # cat case_2.sh
    echo "Which is your preferred PI?"
    read -p "Aruino,pcDuino,RaspberryPi,Cubieboard,OrangePi,BananaPi: " pi
    case $pi in
    [Aa]*|[Pp]*)
        echo "You selected Arduino/pcDuino." ;;
    [Bb]*|[Cc]*|[Oo]*)
        echo "You selected Cubieboard/Banana Pi/OrangePi." ;;
    [Rr]*)
        echo "You selected Raspberry Pi." ;;
    *)
        echo "I don't know which PI you like." ;;
    esac
    
  4. 示例:mysql多实例启动脚本

    # cat case_2.sh
    port=3306
    mysql_user="root"
    mysql_pwd="oldboy"
    CmdPath="/application/mysql/bin"
    
    function_start_mysql(){
        printf "Starting Mysql...\n"
        /bin/bash ${CmdPath}/mysqld_safe --defaults-file=/data/${port}/my.cnf > /dev/null 2>&1 &
    }
    
    function_stop_mysql(){
        printf "Stoping Mysql...\n"
        ${CmdPath}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S /data/${port}/mysql.sock shutdown
    }
    
    function_restart_mysql(){
        printf "restarting Mysql...\n"
        function_stop_mysql
        sleep2
        function_start_mysql
    }
    
    case $1 in
    start)
        function_start_mysql
    ;;
    stop)
        function_start_mysql
    ;;
    restart)
        function_start_mysql
    ;;
    *)
        printf "Usage: /data/${port}/mysql {start|stop|restart}\n"
    ;;
    esac
    
  5. 系统标杆脚本:

    /etc/init.d/functions
    /etc/rc.d/rc.sysinit
    /etc/init.d/nfs
    /etc/init.d/portmap
    /etc/init.d/httpd
    

3-11 while循环与until循环

  1. 语法:while条件句 //条件满足一直做

    while 条件
        do
        指令…
    done
    
  2. 示例:while,每2秒打印uptime情况

    # cat while_1.sh
    while true
    do
        uptime
        sleep 2
    done
    

    说明:while true表示条件永远为真,因此会一直运行,像死循环,因此称为守护进程

    # cat while_2.sh
    while [1]
    do
        uptime >> ./a.log
    #usleep表示微秒
        usleep 2000000
    done
    

    说明: while [ 1 ]相当于while true

    功能 用途
    sh while_1.sh & 把脚本放在后台执行
    ctrl+c 停止执行当前脚本或任务
    ctrl+z 暂停执行当前脚本或任务
    bg b把当前脚本或任务放在后台执行
    fg 当前脚本或任务拿到前台执行,如果有多个任务,可以fg加任务编号调出,如fg 1
    jobs c查看执行的脚本或任务
  3. 示例:while实现1-100之和

    # cat while_3.sh
    i=1
    while [ $i -le 100 ]
    do
        ((j=j+i))
        ((i++))
    done
    echo $j
    
    # seq 100 | tr '\n' '+'| sed 's#\+$#\n#g' | bc
    5050
    
  4. 示例:while实现输入数字与随机数相同,否则一直输入

    # cat while_4.sh
    num=$((RANDOM%100))        #产生一个2位数的随机数
    while :
    do
        read -p "Please guess my number [0-99]: " answer
        if [ $answer -lt $num ]
        then 
            echo "The number you inputed is less then my NUMBER."
        elif [[ $answer -gt $num ]]
        then 
            echo "The number you inputed is greater then my NUMBER."
        elif ((answer==num))
        then 
            echo "Bingo! Congratulate: my NUMBER is $num."
            break
        fi
    done
    
  5. 示例:将当前路径下文件中带空格的替换为_

    # cat while_5.sh
    DIR="."
    find $DIR -type f | while read file; do
    echo $file
    if [[ "$file" = *[[:space:]]* ]]; then
        mv "$file" $(echo $file | tr ' ' '_')
    fi
    done
    
  6. 示例:输入字符串,直到输入OK为止

    # cat while_6.sh
    echo -e "please input values"
    read variable
    while [[ $variable != OK ]]; do
        read variable
        echo $variable
    done
    
  7. until示例

    # cat until_1.sh
    username=$1
    if [ $# -lt 1 ] ; then
        echo "Usage: `basename $0` <username> [<message>]"
        exit 1
    fi
    if grep "^$username:" /etc/passwd > /dev/null ; then :
    else
        echo "$username is not a user on this system."
        exit 2
    fi
    until who|grep "$username" > /dev/null ; do
        echo "$username is not logged on."
        sleep 5
    done
    

    说明:输入用户参数为1,并在/etc/passwd中,直到输入用户为登陆用户,结束循环

    exit命令,直接退出shell脚本

3-14 for循环

  1. 语法结构:

    for 变量名 in 变量取值列表
    do
        指令…
    done
    

    提示:在此结构中"in变量取值列表"可省略,省略时相当于in"$@"

  2. 示例:打印54321

    # cat for_1.sh
    for num in 5 4 3 2 1
    do
        echo $num
    done
    
  3. 示例:打印9 x 9乘法表

    # cat for_2.sh
    for a in `seq 9`
    do
        for b in `seq 9`
        do
            [ $a -ge $b ] && echo -en "$a x $b = $(expr $a \* $b) "
        done
        echo " "
    done
    
  4. 示例:批量创建用户并设置密码

    # cat for_3.sh
    for n in `seq -w 10`
    do
        useradd oldboy-$n
        echo "$n" | passwd --stdin oldboy-$n
    done
    
  5. 示例:变量为可执行命令

    # cat for_4.sh
    for x in ls "df -h" "du -sh"
    do
        echo "==X==";eval $x
    done
    
  6. 示例:不带列表for循环

    # cat for_5.sh
    i=1
    for day ; do
        echo -n "Positional parameter $((i++)): $day "
    case $day in
        [Mm]on|[Tt]ue|[Ww]ed|[Tt]hu|[Ff]ri)
        echo " (weekday)"
    ;;
        [Ss]at|[Ss]un)
        echo " (WEEKEND)"
    ;;
        *) echo " (Invalid weekday)"
    ;;
    esac
    done
    # sh for_5.sh Mon Tue wed Thu Fri sat Sun ok
    Positional parameter 1: Mon  (weekday)
    Positional parameter 2: Tue  (weekday)
    Positional parameter 3: wed  (weekday)
    Positional parameter 4: Thu  (weekday)
    Positional parameter 5: Fri  (weekday)
    Positional parameter 6: sat  (WEEKEND)
    Positional parameter 7: Sun  (WEEKEND)
    Positional parameter 8: ok  (Invalid weekday)
    
  7. 示例:当前目录文件或目录小写改成大写

    # cat for_6.sh
    for fname in * ; do                      # *表示当前路径文件或目录
        fn=$(echo $fname | tr a-z A-Z)       # tr为替换命令
        [ $fname != $fn ] && mv $fname $fn
    done
    
  8. 示例:查看能否ping通

    # cat for_7.sh
    for host in 13.50.1.10 13.50.1.11
    do
        if ping -c2 -w2 $host &>/dev/null
    then
        echo "Host ($host) is active."
    else
        echo "Host ($host) is DOWN."
    fi
    done
    

4-1 系统产生随机数

  1. 通过系统变量RANDOM

    # echo $RANDOM
    23368
    # echo $RANDOM
    31842
    
  2. 通过openssl

    # openssl rand -base64 8
    dPsBSQpkh3w=
    # openssl rand -base64 8
    Gn6zhZb9Vws=
    
  3. 通过时间(date)获得随机数

    [root@localhost soft]# date +%s%N
    1581779690031931743
    [root@localhost soft]# date +%s%N
    1581779690891747018
    
  4. 通过UUID

    # cat /proc/sys/kernel/random/uuid
    b8181971-0e11-4aba-aabc-a201cb789f97
    # cat /proc/sys/kernel/random/uuid
    ded3507e-46b5-4dba-9824-e10c6ffc6a4d
    
  5. 随机数长短不一,如何统一格式化?使用md5sum命令

    # openssl rand -base64 8 | md5sum | cut -c 1-9
    eabe255d6
    # openssl rand -base64 8 | md5sum | cut -c 1-9
    57025849e
    

4-2 break、continue、exit

命令 说明
break [n] n表示跳出循环的层数,如果省略n表示跳出整个循环
continue [n] n表示退到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环
exit [n] 退市当前shell程序,并返回n
return 返回函数执行状态的值
posted @ 2021-03-15 17:21  那就这样吧~  阅读(63)  评论(0编辑  收藏  举报