简单的练习


重要的知识点:

  • bash执行脚本是在当前脚本的bash的子进程bash下执行
  • source执行脚本是在当前进程中执行

代码范例:

  1. #!/bin/bash
  2. #Program:
  3. # This program shows "Hello world!" in your screen
  4. # These Codes are example's codes in <鸟哥的私房菜1>
  5. #history:
  6. #2021/11/9 suyisong First release
  7. #
  8. #知识点:
  9. # bash执行是在子进程中执行的
  10. # source可以在父进程执行
  11. __hello(){
  12. echo -e "Hello World! \a \n"
  13. exit 1 #可作为程序的返回值$?
  14. }
  15. # 交互式脚本
  16. __interactive(){
  17. read -rp "Please input your first name: " firstname
  18. read -rp "Please input your last name: " lastname
  19. echo -e "\nYour full name is ${firstname} ${lastname}"
  20. }
  21. # 建立与日期相关的文件
  22. __date(){
  23. echo -e "I will use 'touch' command to create 3 files."
  24. read -rp 'Please input your filename: ' fileuser
  25. filename=${fileuser:-'datefile'}
  26. date1=$(date --date="-1 days" +%Y%m%d)
  27. date2=$(date --date="-2 days" +%Y%m%d)
  28. date3=$(date +%Y%m%d)
  29. file1=${filename}-${date1}
  30. file2=${filename}-${date2}
  31. file3=${filename}-${date3}
  32. touch "${file1}" "${file2}" "${file3}"
  33. }
  34. # 進行一些數值运算
  35. # 可以通过$(()) | declare -i | bc进行运算
  36. __numberic(){
  37. echo -e 'You should input 2 numbers, I will multipying them!\n'
  38. read -rp "first number: " firstnu
  39. read -rp "second number: " secondnu
  40. total=$((firstnu*secondnu))
  41. echo -e "\nThe result of ${firstnu} x ${secondnu} is ==> ${total}"
  42. }
  43. __pi(){
  44. echo -e "This program will calculate pi value. \n"
  45. echo -e "You should input a float number to calculate pi value.\n"
  46. read -rp "The scale number(10-10000)?" checking
  47. num=${checking:-"10"}
  48. echo -e "Starting calcuate pi value. Be patient."
  49. time echo "scale=${num}; 4*a(1)" | bc -lq
  50. }
  51. __main(){
  52. # __hello
  53. __interactive
  54. # __date
  55. # __numberic
  56. # __pi
  57. }
  58. __main

执行shell的三种方式

  • 直接命令执行: ./index.sh或者/dir/to/index.sh,需要文件有rx全选
  • bash执行: bash index.sh, 需要有x权限
  • source或. : source index.sh或者. index.sh | 执行方式 | 描述 | 区别 | | —- | —- | —- | | 直接命令执行 | |
    - 生成进程,可通过ps -e查看
    - 子进程bash中执行
    | | bash执行 | |
    - 由bash执行对应命令,无法通过ps -e查看
    - 生成子bash在子进程bash中执行
    | | source | |
    - 由bash执行对应命令,无法通过ps -e查看
    - 在父bash中执行
    |

判断式用法


知识点:

  • test命令可以进行逻辑判断
  • 可以用[]来代替test命令
  • shell的传参
  • shift进行参数偏移

test命令的测试功能


核心: test命令可以用于测试各种逻辑, 逻辑true则$?为0. 可以用于各种逻辑运算.

test常用的测试参数:

参数 意义
文件名和文件类型判断, 如test -e filename表示文件是否存在
-e 文件名是否存在
-f 文件名存在且为file
-d 文件名存在且为目录
-b 文件名存在且为block device设备
-c 文件名存在且为一个字符设备文件
-S 文件名存在且为sockets文件
-p 文件名存在且为fifo文件
-L 文件名存在且为链接文件
文件权限判断
-r 文件且在且可读
-w 可写
-x 可执行
-u 文件名存在且具有SUID属性
-g SGID
-k 文件名存在且具有Sticky bit属性
-s 文件非空
文件之间的比较, 如test file1 -nt file2
-nt 判断file1比file2新
-ot 判断file1比file2旧
-ef 判断f1与f2是否为同一个文件, 根据inode判断
两个整数之间的判定: test n1 -eq n2
-eq 两数值相等
-ne 两数值不等
-gt n1 > n2
-lt n1 < n2
-ge n1 >= n2
-le n1 <= n2
判定字符串的数据
test -z sting 判定字符串是否为空, 空则true
test -n string 字符串不为空
test str1 == str2
test str1 != str2
多重条件判定: test -r filename -a -x filename
-o
-a
!

示例:

#!/bin/bash
#Program:
#   This program shows "Hello world!" in your screen
#   These Codes are example's codes in <鸟哥的私房菜1>
#history:
#2021/11/9 suyisong First release 
#
# 知识点:
#   test命令为true则$?=0; 负责为1

# test命令一般用法
__test(){
    echo -e "Please input a filename, I will check the filename's type and permission:\n\n"

    read -rp "Input a filename: " filename

    test -z "${filename}" && echo "You must input a filename." && exit 0

    test ! -e "${filename}" && echo "The filename ${filename} do not exist" && exit 0

    test -f "${filename}" && filetype="regular file"
    test -d "${filename}" && filetype="directory"
    test -r "${filename}" && perm="readable"
    test -w "${filename}" && perm="${perm} writable"
    test -x "${filename}" && perm="${perm} executable"

    echo "The filename: ${filename} is a ${filetype}"
    echo "And the permissions for you are : ${perm}"
}

# 中括号的用法
__bracket(){
    read -rp "Please input (Y/N): " yn
    [ "${yn}" == "Y" ] || [ "${yn}" == "y" ] && echo "Ok, continue" && exit 0
    [ "${yn}" == "N" ] || [ "${yn}" == "n" ] && echo "Oh, interrupt!" && exit 0
    echo "I don't konw what your choice is" && exit 0
}

# 命令行给脚本传参方法
# $# $0 $1 $2 $3
# 参数个数 文件名 第一个参数 第二个参数
__param(){
    echo "The script name is ==> ${0}"
    echo "Total parameter number is ==> ${#}"
    [ "$#" -lt 2 ] && echo "The number of parameter is less then 2. Stop here" && exit 0
    echo "Your whole parameter is ==> '$*'"
    echo "The 1st parameter ==>${1}"
    echo "The 2nd parameter ==>${2}"
}

# shift命令可以移除前n个参数
__shift_param(){
    echo "Total parameter number is ==> ${#}"
    echo "Your whole parameter is ==> '$@'"
    shift
    echo "Total parameter number is ==> ${#}"
    echo "Your whole parameter is ==> '$@'"
    shift 3
    echo "Total parameter number is ==> ${#}"
    echo "Your whole parameter is ==> '$@'"
}


# __test
# __bracket
# __param "$@"
__shift_param "$@"

条件判断式用法


知识点:

  • if和case的用法

练习:

#!/bin/bash
#Program:
#   This program shows "Hello world!" in your screen
#   These Codes are example's codes in <鸟哥的私房菜1>
#history:
#2021/11/10 suyisong First release 
#


__if(){
    read -rp "Please input (Y/N): " yn
    if [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]; then
        echo "Ok, continue"
        exit 0
    fi
    if [ "${yn}" == "N" ] || [ "${yn}" == "n" ]; then
        echo "Oh, interrupt!"
        exit 0
    fi
    echo "I don't konw what your choice is" && exit 0
}

__if_else(){
    read -rp "Please input (Y/N): " yn
    if [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]; then
        echo "Ok, continue"
        exit 0
    elif [ "${yn}" == "N" ] || [ "${yn}" == "n" ]; then
        echo "Oh, interrupt!"
        exit 0
    else
        echo "I don't konw what your choice is" && exit 0
    fi
}

__hello(){
    if [ "${1}" == "hello" ]; then
        echo "Hello, how are you!"
    elif [ -z "${1}" ]; then
        echo "You must input parameters, ex>{${0} someword}"
    else
        echo "The only parameter is 'hello', ex>{${0} hello}"
    fi
}

# 一个demo
# 描述: 当兵退伍时输入退伍日期, 计算还有多少天退伍
__demo(){
    echo "This parogram will try to calculate : "
    echo "How many days before your demobilization date..."
    read -rp "Please input your demobilization date (YYYMMDD ex>20150716):" date2
    date_d=$(echo "${date2}" | grep '[0-9]\{8\}')
    if [ -z "${date_d}" ]; then
        echo "You input the wrong date format..."
        exit 1
    fi
    declare -i date_dem=$(date --date="${date2}" +%s)
    declare -i date_now=$(date +%s)
    declare -i date_total_s=$((date_dem - date_now))
    declare -i date_d=$((date_total_s/60/60/24))
    if [ "${date_total_s}" -lt "0" ]; then
        echo "You had been demobilization before: " $(( -1 * date_d )) " ago"
    else
        declare -i date_h=$(( $((date_total_s-date_d*60*60*24))/60/60 ))
        echo "You will demobilize after ${date_d} days and ${date_h} hours"
    fi
}

__case(){
    case "${1}" in
        "hello")
            echo "Hello, how are you!"
        ;;
        "")
            echo "You must input parameters, ex>{${0} someword}"
        ;;
        *)
            echo "The only parameter is 'hello', ex>{${0} hello}"
        ;;
    esac
}

__printit(){
    echo -n "Your choice is "; echo "${1}" | tr 'a-z' 'A-Z'
}

__func(){
    echo "This program will print your selection !"
    case "${1}" in
        "one"|"two"|"three")
            __printit "${1}"
        ;;
        *)
            echo "Usage ${0} {one|two|three}"
        ;;
    esac

}


# __if
# __if_else

# __hello $@
# __demo
# __case $@
__func $@

循环


知识点:

  • while do done和until do done可以根据条件循环
  • for do done 时固定循环
  • 产生随机数的方法seq 1 100和{1..100}
  • for do done的第二种语法
  • 数组和随机数的搭配

练习:

#!/bin/bash
#Program:
#   This program shows "Hello world!" in your screen
#   These Codes are example's codes in <鸟哥的私房菜1>
#history:
#2021/11/9 suyisong First release 
#

__while(){
    while [ "${yn}" != "yes" -a "${yn}" != "YES" ]; do
        read -rp "please input yes/YES to stop:" yn
    done
    echo "OK! you input the correct answer."
}

__until(){
    until [ "${yn}" == "yes" -o "${yn}" == "YES" ]; do
        read -rp "please input yes/YES to stop:" yn
    done
    echo "OK! you input the correct answer."
}

__cal_1_100(){
    s=0
    i=0
    while [ "${i}" != "100" ]; do
        i=$((i+1))
        s=$((s+i))
    done
    echo "The Result of '1+2+3+...+100' is ==> ${s}"
    unset s
    unset i
}

__for(){
    for animal in dog cat elephant; do
        echo "There are ${animal}s..."
    done
}

__for_passwd(){
    users=$(cut -d ':' -f1 /etc/passwd)
    for user in $users;do
        id "${user}"
    done
}

# seq可以产生连续的字符, {1..100}也能产生连续的字符
__for_ping(){
    network="192.168.1"
    for sitenu in $(seq 1 100); do
        ping -c 1 -w 1 ${network}."${sitenu}" &>/dev/null && result=0 || result=1
        if [ "${result}" == 0 ]; then
            echo "Server ${network}.${sitenu} is UP."
        else
            echo "Server ${network}.${sitenu} is DOWN."
        fi
    done
}

__for_2(){
    read -rp "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}"
}

# 示例
# 随机获取中午吃什么
__demo(){
    eat[1]="肯当当汉堡"
    eat[2]="肯爷爷汉堡"
    eat[3]="彩虹日式便当"
    eat[4]="曱甴"
    eat[5]="乡干部处"
    eat[6]="hah"
    eat[7]="ddd"
    eat[8]="附近哈"
    eat[9]="就会发"
    eatnum=9
    eated=0
    while [ "${eated}" -lt 3 ]; do
        check=$(( RANDOM * eatnum /32767 + 1 ))
        mycheck=0
        if [ "${eated}" -ge 1 ]; then
            for i in $(seq 1 ${eated}); do
                if [ "${eatedcon[$i]}" == $check ]; then
                    mycheck=1
                fi
            done
        fi
        if [ ${mycheck} == 0 ]; then
            echo "your may eat ${eat[$check]}"
            eated=$(( eated + 1 ))
            eatedcon[${eated}]=${check}
        fi
    done

}

# __while
# __until

# __cal_1_100
# __for
# __for_passwd
# __for_ping
# __for_2
__demo

shell脚本的跟踪与调试


核心: 使用bash命令直接进行调试.

bash [-nvx] file
选项与参数:
-n : 不执行脚本仅查询语法
-v : 执行脚本前先输出脚本
-x : 将使用到的脚本内容输出

重点:


  • sh -x .sh进行程序的debug