• 鸟哥的linux私房菜——第十二章学习(Shell Scripts)


    第十二章  Shell Scripts

    1.0)、什么是shell scripts?

    script 是“脚本、剧本”的意思。整句话是说, shell script 是针对 shell 所写的“剧本!”

    shell script 是利用 shell 的功能所写的一个“程序 program)”,这个程序是使用纯文本文件,将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。

    就像是早期 DOS 年代的批处理文件 .bat ,最简单的功能就是将许多指令汇整写在一起,不需要编译即可执行

    1.1)、shell scripts优点

    l 自动化管理的重要依据

    l 追踪与管理系统的重要工作

    l 简单入侵侦测功能

    l 连续指令单一化

    l 简易的数据处理

    l 跨平台支持与学习历程较短

    2.0)、第一支script 的撰写与执行

    注意事项:

    1. 指令的执行是从上而下、从左而右的分析与执行;

    2. 指令的下达就如同第四章内提到的: 指令、选项与参数间的多个空白都会被忽略掉;

    3. 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;

    4. 如果读取到一个 Enter 符号 CR ,就尝试开始执行该行 (或该串) 命令;

    5. 至于如果一行的内容太多,则可以使用“ [Enter] ”来延伸至下一行;

    6. “ # ”可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!

    假设shell.sh文件在/home/dmtsai/目录下,那么执行sh文件方式:

    l 直接指令下达:shell.sh 文件必须要具备可读与可执行 rx 的权限,然后:

    • 绝对路径:使用 /home/dmtsai/<filename>.sh 来下达指令;
    • 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来执行;
    • 变量“PATH”功能:将 shell.sh 放在 PATH 指定的目录内,例如: “ ~/bin/ ”。

    l 以bash程序来执行:通过“bash <filename>.sh”或者“sh <filename>.sh

    解析:

    因为 /bin/sh 其实就是 /bin/bash (链接文件),使用 sh shell.sh 亦即告诉系统,我想要直接以bash 的功能来执行 shell.sh 这个文件内的相关指令的意思,

    【第一支script】

    [dmtsai@study ~]$ mkdir bin; cd bin
    [dmtsai@study bin]$ vim hello.sh
    #!/bin/bash
    # Program:
    # This program shows "Hello World!" in your screen.
    # History:
    # 2015/07/16 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    echo -e "Hello World! a 
    "
    exit 0

    注解:

    1、第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称;

    2、整个 script 当中,除了第一行的“ #! ”是用来宣告 shell 的之外,其他的 # 都是“注解”用途;

    3、主要环境变量的宣告PATH;

    4、主要程序部分,就是echo那一行;

    5、执行成果告知:讨论一个指令的执行成功与否,可以使用 $? 这个变量来观察(如接着使用echo $? 即可查询命令是否执行成功),在srcipt中我们也可以利用 exit 这个指令来让程序中断,并且回传一个数值给系统,如exit n(n是一个数字)。

    2.1)、简单的数值运算:+-*,、,%

    运算时,可使用:echo $(( 运算内容 ))

    小数点:| bc“basic calculator”的缩写

    计算PI值:

    [dmtsai@study bin]$ vim cal_pi.sh
    #!/bin/bash
    # Program:
    # User input a scale number to calculate pi number.
    # History:
    # 2015/07/16 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    echo -e "This program will calculate pi value. 
    "
    echo -e "You should input a float number to calculate pi value.
    "
    read -p "The scale number (10~10000) ? " checking
    num=${checking:-"10"} # 开始判断有否有输入数值
    echo -e "Starting calcuate pi value. Be patient."
    time echo "scale=${num}; 4*a(1)" | bc -lq

    注释:

    tan 45°  =1; 45°也可以写作 π/4,四分之派。所以arctan 1echo中的a(1))的值也就是π/4,乘以4当然就是π的值。

     

    2.2)、script的执行方式差异(source, sh script, ./script

     

     

    利用直接执行的方式来执行 script

     

    当子程序完成后,在子程序内的各项变量或动作将会结束而不会传回到父程序中。

     

    意思就是:当你使用直接执行的方法来处理时,系统会给予一支新的 bash 让我们来执行 showname.sh 里面的指令,因此你的 firstname, lastname 等变量其实是在下图中的子程序 bash 内执行的。 showname.sh 执行完毕后,子程序 bash 内的所有数据便被移除,因此上表的练习中,在父程序下面 echo ${firstname} 时, 就看不到任何东西了。类似于局部变量。

     

    利用 source 来执行脚本:在父程序中执行

     

    showname.sh 会在父程序中执行的,因此各项动作都会在原本的 bash 内生效。

     

     

    2.3)、善用判断(test, &&, ||, []

     

    l test, &&, ||

     

    例子:检查 /dmtsai 是否存在时,使用:

     

     

    [dmtsai@study ~]$ test -e /dmtsai && echo "exist" || echo "Not exist"
    Not exist <==结果显示不存在啊!

     

    l []:中括号

    作为判断式时,必须要注意中括号的两端需要有空白字符来分隔。

    注意:

    • 在中括号 [] 内的每个元件都需要有空白键来分隔;
    • 在中括号内的变量,最好都以双引号括号起来;
    • 在中括号内的常数,最好都以单或双引号括号起来。

    如:判断两个字符串是否相等:

     

     

    [dmtsai@study ~]$ name="VBird Tsai"
    [dmtsai@study ~]$ [ ${name} == "VBird" ]
    bash: [: too many arguments

     

    原因就是${name}没有用双引号扩住。

    所以上面解析式会变成:[ VBird Tsai == "VBird" ]

    但是我们期望的是[ "VBird Tsai" == "VBird" ],所以就需要加上引号了。

    另:中括号比较常用在条件判断式 if ..... then ..... fi 的情况中。

    【案例:提示输入交互判断】

     

     

    [dmtsai@study bin]$ vim ans_yn.sh
    #!/bin/bash
    # Program:
    # This program shows the user's choice
    # History:
    # 2015/07/16 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    read -p "Please input (Y/N): " yn
    [ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK, continue" && exit 0
    [ "${yn}" == "N" -o "${yn}" == "n" ] && echo "Oh, interrupt!" && exit 0
    echo "I don't know what your choice is" && exit 0

     

    注解:

    1、由于输入正确 Yes 的方法有大小写之分,不论输入大写 Y 或小写 y 都是可以的,此时判断式内就得要有两个判断才行!

    2、这里使用 -o (或) 链接两个判断。不能用“||”。

    l Shell Script 的默认变量($0, $1...)

     read 功能的问题是你得要手动由键盘输入一些判断式。

    通过指令后面接参数, 那么一个指令就能够处理完毕而不需要手动再次输入一些变量行为

     

     

    /path/to/scriptname opt1 opt2 opt3 opt4
            $0           $1   $2   $3   $4

     

    • $# :代表后接的参数“个数”,以上表为例这里显示为“ 4 ”;
    • $@ :代表“ "$1" "$2" "$3" "$4" ”之意,每个变量是独立的(用双引号括起来);
    • $* :代表“ "$1c$2c$3c$4" ”,其中 c 为分隔字符,默认为空白键, 所以本例中代表“ "$1 $2 $3 $4" ”之意。

     

     

    2.4)、条件判断式(if...then, case...esac, function

     

    l if...then

     

     

    if [ 条件判断式 ]; then
    当条件判断式成立时,可以进行的指令工作内容;
    fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意!

     

     && 代表 AND ;

    || 代表 or ;

    所以:

     

     

    [ "${yn}" == "Y" -o "${yn}" == "y" ]
    上式可替换为
    [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]

     

    多重判断:

     

    # 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况执行
    if [ 条件判断式一 ]; then  <==【if和[之间有空格】
    当条件判断式一成立时,可以进行的指令工作内容;
    elif [ 条件判断式二 ]; then
    当条件判断式二成立时,可以进行的指令工作内容;
    else
    当条件判断式一与二均不成立时,可以进行的指令工作内容;
    fi

    l case...esac

    [dmtsai@study bin]$ vim hello-3.sh
    #!/bin/bash
    # Program:
    # Show "Hello" from $1.... by using case .... esac
    # History:
    # 2015/07/16 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    case ${1} in
    "hello")
    echo "Hello, how are you ?"
    ;;
    "")
    echo "You MUST input parameters, ex> {${0} someword}"
    ;;
    *) # 其实就相当于万用字符,0~无穷多个任意字符之意!
    echo "Usage ${0} {hello}"
    ;;
    esac

    l function

    [dmtsai@study bin]$ vim show123-3.sh
    #!/bin/bash
    # Program:
    # Use function to repeat information.
    # History:
    # 2015/07/17 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    function printit(){
      echo "Your choice is ${1}" # 这个 $1 必须要参考下面指令的下达
    }
    echo "This program will print your selection !"
    case ${1} in
      "one")
        printit 1 # 请注意, printit 指令后面还有接参数!
        ;;
      "two")
        printit 2
        ;;
      "three")
        printit 3
        ;;
      *)
        echo "Usage ${0} {one|two|three}"
        ;;
    esac

    输入“ sh show123-3.sh one ”就会出现“ Your choice is 1 ”,“ printit 1 ”中那个 1 就会成为 function 当中的 $1 。

    function 也是拥有内置变量的~他的内置变量与 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来取代。

    特别注意的是,“ function fname() { 程序段 } ”内的 $0, $1... 等等与 shell script $0 是不同的。

    l 常见的port与网络服务关系:

    80: WWW

    22: ssh

    21: ftp

    25: mail

    111: RPC(远端程序调用)

    631: CUPS(打印服务功能)

    2.5)、循环(loop

    循环可以不断的执行某个程序段落,直到使用者设置的条件达成为止。

    循环又分为不定循环和固定循环。

    不定循环:while do done, until do done

    • while do done
    while [ condition ] <==中括号内的状态就是判断式【while和[之间有空格】
    do <==do 是循环的开始!
    程序段落
    done <==done 是循环的结束

    例子:

    [dmtsai@study bin]$ vim yes_to_stop.sh
    #!/bin/bash
    # Program:
    # Repeat question until user input correct answer.
    # History:
    # 2015/07/17 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    while [ "${yn}" != "yes" -a "${yn}" != "YES" ]
    do
    read -p "Please input yes/YES to stop this program: " yn
    done
    echo "OK! you input the correct answer."
    • until do done

    接上述例子:

    [dmtsai@study bin]$ vim yes_to_stop-2.sh
    #!/bin/bash
    # Program:
    # Repeat question until user input correct answer.
    # History:
    # 2015/07/17 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    until [ "${yn}" == "yes" -o "${yn}" == "YES" ]
    do
    read -p "Please input yes/YES to stop this program: " yn
    done
    echo "OK! you input the correct answer."

     注:-a 表示且的意思,-o 表示或的意思。

    【举例:计算1--100的和】

    [dmtsai@study bin]$ vim cal_1_100.sh
    #!/bin/bash
    # Program:
    # Repeat question until user input correct answer.
    # History:
    # 2015/07/17 VBird First release
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    export PATH
    
    echo "this program is to calculate from 1 to 100."
    read -p "Now do u want to start(y/n)?" yn
    sum=0;
    if [ "${yn}" == "y" -o "${yn}" == "Y" ]; then
            i=0;
            while [ "${i}" -le "100" ] # 可换成for i in $(seq 1 100)
            do
                    echo " i = ${i} "
                    sum=$(( $sum+$i ))
                    i=$(( $i+1 ))
            done
            echo "1+2+...+100 = ${sum}"
    elif [ "${yn}" == "n" -o "${yn}" == "N" ]; then
            echo "U dont want to calculate,if u want, plz retry and input y."
    else
            echo "I dont your choose."
    fi
    exit 0

    上述中的while [...]这一行还可以换成for i in $(seq 1 100)

    seq表示连续的。其缩写为{1..100} 来取代 $(seq 1 100)

    固定循环for...do...done

    for的用法有两种:

    • 第一种:
    for var in con1 con2 con3 ...
    do
        程序段
    done

    注:

    1. 第一次循环时, $var 的内容为 con1 ;

    2. 第二次循环时, $var 的内容为 con2 ;

    3. 第三次循环时, $var 的内容为 con3 ;

    依次循环。

    • 第二种:
    for(( 初始值; 限制值; 执行步阶))  <==【for和(之间可以有空格,也可没有】
    do
        程序段
    done

    1.初始值:某个变量在循环当中的起始值,直接以类似 i=1 设置好;

    2.限制值:当变量的值在这个限制值的范围内,就继续进行循环。例如 i<=100;

    3.执行步阶:每作一次循环时,变量的变化量。例如 i=i+1,亦可写成i++。

    除了使用大小等于符号之外,还有如下符号表示:

    -eq

    等于

    -ne

    不等于

    -gt

    大于

    -lt

    小于

    -ge

    大于等于

    -le

    小于等于

    注意:

    语法问题:

    if [ 条件判断式一 ]; then  <==【if和[之间必须有空格】

    while [ condition ] <==中括号内的状态就是判断式【while和[之间必须有空格】

    for(( 初始值; 限制值; 执行步阶))  <==【for和(之间可以有空格,也可没有】

    3.0)、追踪(debug

    debug

    [dmtsai@study ~]$ sh [-nvx] scripts.sh
    选项与参数:
    -n :不要执行 script,仅查询语法的问题;
    -v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
    -x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!
    范例一:测试 dir_perm.sh 有无语法的问题?
    [dmtsai@study ~]$ sh -n dir_perm.sh
    # 若语法没有问题,则不会显示任何信息!
    范例二:将 show_animal.sh 的执行过程全部列出来~
    [dmtsai@study ~]$ sh -x show_animal.sh
    + PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin
    + export PATH
    + for animal in dog cat elephant
    + echo 'There are dogs.... '
    There are dogs....
    + for animal in dog cat elephant
    + echo 'There are cats.... '
    There are cats....
    + for animal in dog cat elephant
    + echo 'There are elephants.... '
    There are elephants....

    【重点回顾】

    1. shell script 是利用 shell 的功能所写的一个“程序 program)”,这个程序是使用纯文本文件,将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的
    2. shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为 Shell scripts 的速度较慢,且使用的CPU 资源较多,造成主机资源的分配不良;
    3. Shell script 的文件中,指令的执行是从上而下、从左而右的分析与执行;
    4. shell script 的执行,至少需要有 r 的权限,若需要直接指令下达,则需要拥有 r x 的权限;
    5. 良好的程序撰写习惯中,第一行要宣告 shell (#!/bin/bash ,第二行以后则宣告程序用途、版本、作者等
    6. 对谈式脚本可用 read 指令达成;
    7. 要创建每次执行脚本都有不同结果的数据,可使用 date 指令利用日期达成;
    8. script 的执行若以 source 来执行时,代表在父程序的 bash 内执行之意!
    9. 若需要进行判断式,可使用 test 或中括号 [] 来处理;
    10. script 内,$0, $1, $2..., $@ 是有特殊意义的!
    11. 条件判断式可使用 if...then 来判断,若是固定变量内容的情况下,可使用 case $var in ... esac 来处理;
    12. 循环主要分为不定循环 while, until 以及固定循环 for ,配合 do, done 来达成所需任务!
    13. 我们可使用 sh -x script.sh 来进行程序的 debug。

    Over...

  • 相关阅读:
    cstc2018 混合果汁
    CF1086E Beautiful Matrix
    AT2000 Leftmost Ball
    CF1208E Let Them Slide
    CF1208D Restore Permutation
    【置顶】博客公告
    [NOI2015]软件包管理器
    【noip2018】积木大赛
    几天连测总结
    【ZJOI2007】棋盘制作
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14303743.html
Copyright © 2020-2023  润新知