zoukankan      html  css  js  c++  java
  • linux shell scripts

    一. 编写shell脚本的准备

    1. shell脚本的内部运行机制

    • 命令的运行是从上而下、从左而右的分析与运行; 
    • 命令的下达: 命令、选项与参数间的多个空白都会被忽略掉; 
    • 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键; 
    • 如果读取到一个 Enter 符号 (CR) ,就尝试开始运行该行 (或该串) 命令; 
    • 至於如果一行的内容太多,则可以使用『 [Enter] 』来延伸至下一行; 
    • 『 # 』可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!

    2. 如何启动shell脚本

    • 直接命令下达: shell.sh 文件必须要具备可读与可运行 (rx) 的权限,然后: (实际上是在bash的子程序里运行)
      • 绝对路径:使用 /home/dmtsai/shell.sh 来下达命令; 
      • 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来运行 
      • 变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/ 
    • 以 bash 程序来运行:透过『 bash shell.sh 』或『 sh shell.sh 』来运行.(实际上是在bash的子程序里运行)
    • 以source来运行脚本(是在父bash程序运行脚本,不推荐)。

    3. shell脚本头部内容

    • script 的功能; 
    • script 的版本资讯; 
    • script 的作者与联络方式; 
    • script 的版权宣告方式; 
    • script 的 History (历史纪录); 
    • script 内较特殊的命令,使用『绝对路径』的方式来下达; 
    • script 运行时需要的环境变量预先宣告与配置。

    4. 编写shell脚本的习惯

    • shell脚本头部建议按照第3点进行完善;
    • 个人建议务必要加上注解说明,可以帮助你非常非常多;
    • 此外,程序码的撰写最好使用巢状方式,在包覆的内部程序码最好能以 [tab] 按键的空格向后推, 这样你的程序码会显的非常的漂亮与有条理!在查阅与 debug 上较为轻松愉快喔;
    • 使用撰写 script 的工具最好使用 vim 而不是 vi ,因为 vim 会有额外的语法检验机制,能够在第一阶段撰写时就发现语法方面的问题。

    二. 简单脚本功能实践

    1. 提示用户输入并拼接用户输入范例

    #!/bin/bash
    # study shell scripts
    # 2020.03.04 auth:jet
    
    PATH=`echo $PATH`
    export PATH
    
    read -p "please input your first name:" first_name
    read -p "please input your second name:" second_name
    echo -e "
     your full name is: $first_name$second_name"

    2. 根据用户输入创建不同日期文件

    #!/bin/bash
    # study touch different date file
    # 2020.03.05 auth:jet

    PATH=`echo $PATH`
    export PATH #提示用户输入文件名
    echo -e "I will touch three dinfferent date file." read -p "please input your filename:" fileuser #判断用户是否输入了文件名 filename=${fileuser:-"filename"} #将用户输入的文件名进行不同日期处理 date1=`date --date '2 days ago' +%Y%m%d` date2=`date --date '1 days ago' +%Y%m%d` date3=`date +%Y%m%d` file1=$filename$date1 file2=$filename$date2 file3=$filename$date3 #创建不同日期的文件名 touch $file1 touch $file2 touch $file3

    3. 计算器的演示

    #!/bin/bash
    # this is study cal
    # 2020.03.05 auth:jet
    
    PATH=`echo $PATH`
    export PATH
    
    echo -e "this is a * cal"
    read -p "pls input a:" a
    read -p "pls input b:" b
    
    x=$(($a*$b))
    
    echo -e "a*b=$x"

    三. 学习判断工具

    1. test判断工具

    测试的标志    代表意义
    1. 关於某个档名的『文件类型』判断,如 test -e filename 表示存在否
    -e    该『档名』是否存在?(常用)
    -f    该『档名』是否存在且为文件(file)?(常用)
    -d    该『档名』是否存在且为目录(directory)?(常用)
    -b    该『档名』是否存在且为一个 block device 装置?
    -c    该『档名』是否存在且为一个 character device 装置?
    -S    该『档名』是否存在且为一个 Socket 文件?
    -p    该『档名』是否存在且为一个 FIFO (pipe) 文件?
    -L    该『档名』是否存在且为一个连结档?
    2. 关於文件的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外)
    -r    侦测该档名是否存在且具有『可读』的权限?
    -w    侦测该档名是否存在且具有『可写』的权限?
    -x    侦测该档名是否存在且具有『可运行』的权限?
    -u    侦测该档名是否存在且具有『SUID』的属性?
    -g    侦测该档名是否存在且具有『SGID』的属性?
    -k    侦测该档名是否存在且具有『Sticky bit』的属性?
    -s    侦测该档名是否存在且为『非空白文件』?
    3. 两个文件之间的比较,如: test file1 -nt file2
    -nt    (newer than)判断 file1 是否比 file2 新
    -ot    (older than)判断 file1 是否比 file2 旧
    -ef    判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判定,两个文件是否均指向同一个 inode 哩!
    4. 关於两个整数之间的判定,例如 test n1 -eq n2
    -eq    两数值相等 (equal)
    -ne    两数值不等 (not equal)
    -gt    n1 大於 n2 (greater than)
    -lt    n1 小於 n2 (less than)
    -ge    n1 大於等於 n2 (greater than or equal)
    -le    n1 小於等於 n2 (less than or equal)
    5. 判定字串的数据
    test -z string    判定字串是否为 0 ?若 string 为空字串,则为 true
    test -n string    判定字串是否非为 0 ?若 string 为空字串,则为 false。
    注: -n 亦可省略
    test str1 = str2    判定 str1 是否等於 str2 ,若相等,则回传 true
    test str1 != str2    判定 str1 是否不等於 str2 ,若相等,则回传 false
    6. 多重条件判定,例如: test -r filename -a -x filename
    -a    (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限时,才回传 true-o    (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true!    反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true
    test工具详解
    #!/bin/bash
    # this is study test
    # 2020.03.05 auth:jet
    
    PATH=`echo $PATH`
    export=PATH
    
    # 1. 让使用者输入档名,并且判断使用者是否真的有输入字串?
    
    echo -e "Please input a filename, I will check the filename's type and 
    
    permission. 
    
    "
    
    read -p "Input a filename : " filename
    
    test -z $filename && echo "You MUST input a filename." && exit 0
    
    # 2. 判断文件是否存在?若不存在则显示信息并结束脚本
    
    test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0
    
    # 3. 开始判断文件类型与属性
    
    test -f $filename && filetype="regulare file"
    
    test -d $filename && filetype="directory"
    
    test -r $filename && perm="readable"
    
    test -w $filename && perm="$perm writable"
    
    test -x $filename && perm="$perm executable"
    
    # 4. 开始输出资讯!
    
    echo "The filename: $filename is a $filetype"
    
    echo "And the permissions are : $perm"
    test使用范例

    2. 利用判断符号 [ ]

    中括号的使用方法与 test的用法一致,区别在于表现形式,中括号的使用需要注意如下几点:

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

    举个例子,判断两个变量是否相等。

    举例1:
    [ "$HOME" == "$MAIL" ] [□"$HOME"□==□"$MAIL"□] ↑ ↑ ↑ ↑

    举例2:
    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
     

    3. shell scripts的默认变量

    脚本的默认变量的位置

    /path/to/scriptname  opt1  opt2  opt3  opt4 
    
           $0             $1    $2    $3    $4
    #!/bin/bash
    PATH=`echo $PATH`
    export PATH
    
    echo "The script name is        ==> $0"
    
    echo "Total parameter number is ==> $#"    # "$#"代表后接的参数『个数』
    
    [ "$#" -lt 2 ] && echo "The number of parameter is less than 2.  Stop here." && exit 0
    
    echo "Your whole parameter is   ==> '$@'"   # "$@"代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
    echo
    "Your whole parameter is ==> '$*'" # "$*"代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键
    echo "The 1st parameter         ==> $1"
    echo "The 2nd parameter         ==> $2"

    4. shell scripts 变量偏移

    #代码:
    echo "Total parameter number is ==> $#"
    
    echo "Your whole parameter is   ==> '$@'"
    
    shift   # 进行第一次『一个变量的 shiftecho "Total parameter number is ==> $#"
    
    echo "Your whole parameter is   ==> '$@'"
    
    shift 3 # 进行第二次『三个变量的 shiftecho "Total parameter number is ==> $#"
    
    echo "Your whole parameter is   ==> '$@'"
    
    #运行结果:
    [root@www scripts]# sh sh08.sh one two three four five six <==给予六个参数
    
    Total parameter number is ==> 6   <==最原始的参数变量情况
    
    Your whole parameter is   ==> 'one two three four five six'
    
    Total parameter number is ==> 5   <==第一次偏移,看底下发现第一个 one 不见了
    
    Your whole parameter is   ==> 'two three four five six'
    
    Total parameter number is ==> 2   <==第二次偏移掉三个,two three four 不见了
    
    Your whole parameter is   ==> 'five six'

    四. 条件判断语句

    1. if判断语句

    基础if语句语法:
    
    if [ 条件判断式 ]; then
    
        当条件判断式成立时,可以进行的命令工作内容;
    
    fi   <==将 if 反过来写,就成为 fi 啦!结束 if 之意!
    
    #注意,在中括号判断中&& 代表 AND ;|| 代表 or ;但是亲自测试结果是&& ||不好用,会报语法错误,所以还是老老实实的用-a -o 把。
    # 一个条件判断,分成功进行与失败进行 (else)
    
    if [ 条件判断式 ]; then
    
        当条件判断式成立时,可以进行的命令工作内容;
    
    else
    
        当条件判断式不成立时,可以进行的命令工作内容;
    
    fi
    # 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况运行
    
    if [ 条件判断式一 ]; then
    
        当条件判断式一成立时,可以进行的命令工作内容;
    
    elif [ 条件判断式二 ]; then
    
        当条件判断式二成立时,可以进行的命令工作内容;
    
    else
    
        当条件判断式一与二均不成立时,可以进行的命令工作内容;
    
    fi
    #!/bin/bash
    
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    
    export PATH
    
    
    
    if [ "$1" == "hello" ]; then
    
        echo "Hello, how are you ?"
    
    elif [ "$1" == "" ]; then
    
        echo "You MUST input parameters, ex> {$0 someword}"
    
    else
    
        echo "The only parameter is 'hello', ex> {$0 hello}"
    
    fi
    if范例

    2. case判断语句

    case  $变量名称 in   <==关键字为 case ,还有变量前有钱字号
    
      "第一个变量内容")   <==每个变量内容建议用双引号括起来,关键字则为小括号 )
    
        程序段
    
        ;;            <==每个类别结尾使用两个连续的分号来处理!
    
      "第二个变量内容")
    
        程序段
    
        ;;
    
      *)                  <==最后一个变量内容都会用 * 来代表所有其他值
    
        不包含第一个变量内容与第二个变量内容的其他程序运行段
    
        exit 1
    
        ;;
    
    esac                  <==最终的 case 结尾!『反过来写』思考一下!
    #!/bin/bash
    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
    case范例
    #!/bin/bash
    
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    
    export PATH
    
    
    
    echo "This program will print your selection !"
    
    # read -p "Input your choice: " choice # 暂时取消,可以替换!
    
    # case $choice in                      # 暂时取消,可以替换!
    
    case $1 in                             # 现在使用,可以用上面两行替换!
    
      "one")
    
        echo "Your choice is ONE"
    
        ;;
    
      "two")
    
        echo "Your choice is TWO"
    
        ;;
    
      "three")
    
        echo "Your choice is THREE"
    
        ;;
    
      *)
    
        echo "Usage $0 {one|two|three}"
    
        ;;
    
    esac
    case进阶范例

    3. shell scripts的函数

    function fname() {
    
        程序段
    
    }
    PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
    
    export PATH
    
    
    
    function printit(){
    
        echo -n "Your choice is "     # 加上 -n 可以不断行继续在同一行显示
    
    }
    
    
    
    echo "This program will print your selection !"
    
    case $1 in
    
      "one")
    
        printit; echo $1 | tr 'a-z' 'A-Z'  # 将参数做大小写转换!
    
        ;;
    
      "two")
    
        printit; echo $1 | tr 'a-z' 'A-Z'
    
        ;;
    
      "three")
    
        printit; echo $1 | tr 'a-z' 'A-Z'
    
        ;;
    
      *)
    
        echo "Usage $0 {one|two|three}"
    
        ;;
    
    esac
    函数的使用范例
    #!/bin/bash
    
    # function 也是拥有内建变量的~他的内建变量与 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来取代的~ 这里很容易搞错喔~因为『 function fname() { 程序段 } 』内的 $0, $1... 等等与 shell script 的 $0 是不同的。
    
    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 sh12-3.sh one 』就会出现『 Your choice is 1 』的字样~ 为什么是 1 呢?因为在程序段落当中,我们是写了『 printit 1 』那个 1 就会成为 function 当中的 $1 .
    理解函数变量范例

    五. 循环语句

    1. while循环

    while [ condition ]  <==中括号内的状态就是判断式
    
    do            <==do 是回圈的开始!
    
        程序段落
    
    done          <==done 是回圈的结束
    until [ condition ]
    
    do
    
        程序段落
    
    done
    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."
    while范例
    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."
    until范例
    s=0  # 这是加总的数值变量
    
    i=0  # 这是累计的数值,亦即是 1, 2, 3....
    
    while [ "$i" != "100" ]
    
    do
    
        i=$(($i+1))   # 每次 i 都会添加 1 
    
        s=$(($s+$i))  # 每次都会加总一次!
    
    done
    
    echo "The result of '1+2+3+...+100' is ==> $s"
    1累加到100范例

    2. for循环

    for var in con1 con2 con3 ...
    
    do
    
        程序段
    
    done
    #范例1
    for animal in dog cat elephant
    
    do
    
        echo "There are ${animal}s.... "
    
    done
    
    #范例2
    users=$(cut -d ':' -f1 /etc/passwd)  # 撷取帐号名称
    
    for username in $users               # 开始回圈进行!
    
    do
    
            id $username
    
            finger $username
    
    done
    
    
    #范例3
    network="192.168.1"              # 先定义一个网域的前面部分!
    
    for sitenu in $(seq 1 100)       # seq 为 sequence(连续) 的缩写之意
    
    do
    
        # 底下的程序在取得 ping 的回传值是正确的还是失败的!
    
            ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
    
        # 开始显示结果是正确的启动 (UP) 还是错误的没有连通 (DOWN)
    
            if [ "$result" == 0 ]; then
    
                    echo "Server ${network}.${sitenu} is UP."
    
            else
    
                    echo "Server ${network}.${sitenu} is DOWN."
    
            fi
    
    done
    
    
    #范例4
    # 1. 先看看这个目录是否存在啊?
    
    read -p "Please input a directory: " dir
    
    if [ "$dir" == "" -o ! -d "$dir" ]; then
    
        echo "The $dir is NOT exist in your system."
    
        exit 1
    
    fi
    
    
    
    # 2. 开始测试文件罗~
    
    filelist=$(ls $dir)        # 列出所有在该目录下的文件名称
    
    for filename in $filelist
    
    do
    
        perm=""
    
        test -r "$dir/$filename" && perm="$perm readable"
    
        test -w "$dir/$filename" && perm="$perm writable"
    
        test -x "$dir/$filename" && perm="$perm executable"
    
        echo "The file $dir/$filename's permission is $perm "
    
    done
    for循环用法1范例
    for (( 初始值; 限制值; 运行步阶 ))
    
    do
    
        程序段
    
    done
    read -p "Please input a number, I will count for 1+2+...+your_input: " nu
    
    
    
    s=0
    
    for (( i=1; i<=$nu; i=i+1 ))
    
    do
    
        s=$(($s+$i))
    
    done
    
    echo "The result of '1+2+3+...+$nu' is ==> $s"
    for循环用法2范例

    六. shell脚本debug

    scripts 在运行之前,最怕的就是出现语法错误的问题了,可以在脚本运行之前通过以下方法进行debug。

    [root@www ~]# sh [-nvx] scripts.sh
    
    选项与参数:
    
    -n  :不要运行 script,仅查询语法的问题;,没有问题不会有任何显示。
    
    -v  :再运行 sccript 前,先将 scripts 的内容输出到萤幕上;
    
    -x  :将使用到的 script 内容显示到萤幕上,这是很有用的参数!
  • 相关阅读:
    带你了解 MySQL Binlog 不为人知的秘密
    算法的空间复杂度
    算法的时间复杂度
    xargs--冬天里的一丝暖意
    "三剑客"之awk心中无剑
    hadoop之yarn(优化篇)
    对hadoop RPC的理解
    mysql优化篇(基于索引)
    [python学习手册-笔记]003.数值类型
    [python学习手册-笔记]001.python前言
  • 原文地址:https://www.cnblogs.com/wangzengyi/p/12416368.html
Copyright © 2011-2022 走看看