Shell Shell
Home
Shell
Linux
Network
Git
Blog (opens new window)
GitHub (opens new window)
Home
Shell
Linux
Network
Git
Blog (opens new window)
GitHub (opens new window)
  • Shell 脚本编程

    • 目录
    • 变量的高级用法
      • 变量替换和测试
        • 变量替换
        • 变量测试
      • 字符串处理
        • 计算字符串长度
        • 获取子串字符在字符串中的索引位置
        • 获取子串长度
        • 抽取字符串中的子串
        • 字符串处理练习
      • 命令替换
        • 语法
        • 练习一
        • 练习二
        • 练习三
        • 练习四
      • 有类型变量
        • 声明变量为只读类型
        • 声明变量为整数类型
        • 显示系统定义过的函数名及函数体
        • 声明变量类型为数组
        • 声明变量为环境变量
      • 数学运算 expr
        • 语法
        • 操作符对照表
        • 练习
      • 数学运算 bc
        • 语法
        • 操作符对照表
        • 练习
    • 函数的高级用法
    • 文件查找命令 find
    • 文本处理命令 grep
    • 文本处理命令 sed
  • shell
  • Shell 脚本编程
JaimeZeng
2021-02-21

变量的高级用法

该小节介绍了变量的高级用法,如何进行变量替换、字符串处理方法、如何利用命令替换为变量赋值、有类型变量和变量引用的使用方法,并在实际环境中演示如何使用,加深大家的认识和理解;最后介绍 shell 中的数学运算方法,使用 expr 和 bc...

# 变量替换和测试

# 变量替换

语法 说明
${变量名#匹配规则} 从变量开头进行规则匹配,将符合最短的数据删除
${变量名##匹配规则} 从变量开头进行规则匹配,将符合最长的数据删除
${变量名%匹配规则} 从尾部开头进行规则匹配,将符合最短的数据删除
${变量名%%匹配规则} 从尾部开头进行规则匹配,将符合最长的数据删除
${变量名/旧字符串/新字符串} 变量内容符合旧字符串,则第一个旧字符串会被新字符串取代
${变量名//旧字符串/新字符串} 变量内容符合旧字符串,则全部的旧字符串会被新字符串取代
[ryan@ryan-tencentcloud-1 ~]$ var0="I love you, do you love me"
[ryan@ryan-tencentcloud-1 ~]$ echo $var0
I love you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0#*ov}    # 从头开始匹配,最短删除
e you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0##*ov}    # 从头开始匹配,最长删除
e me
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0%ov*}    # 从尾开始匹配,最短删除
I love you, do you l
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0%%ov*}    # 从尾开始匹配,最长删除
I l
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0/love/hate}    # 替换变量内的第一个旧字符串为新字符串
I hate you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo ${var0//love/hate}    # 替换变量内的所有的旧字符串为新字符串
I hate you, do you hate me
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 变量测试

变量配置方式 str 没有配置 str 为空字符串 str 已配置且非空
var=${str-expr} var=expr var= var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr} var= var=expr var=expr
var=${str:+expr} var= var= var=expr
var=${str=expr} var=expr var= var=$str
var=${str:=expr} var=expr var=expr var=$str

# 字符串处理

# 计算字符串长度

语法 说明
方法一 ${#string} 无
方法二 expr length "$string" string 中有空格就必须要加双引号
[ryan@ryan-tencentcloud-1 ~]$ var0="I love you, do you love me"
[ryan@ryan-tencentcloud-1 ~]$ echo $var0
I love you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo ${#var0}    # ${#string} 方法计算字符串长度
26
[ryan@ryan-tencentcloud-1 ~]$ echo `expr length "$var0"`    # expr length "$string" 方法计算字符串长度
26
1
2
3
4
5
6
7

# 获取子串字符在字符串中的索引位置

语法:expr index $string $substring ,获取子串字符在字符串中的索引位置。子串是字符串,就会将子串切分成单个字符,查找字符在字符串中第一次出现的位置。

[ryan@ryan-tencentcloud-1 ~]$ var0="I love you, do you love me"
[ryan@ryan-tencentcloud-1 ~]$ echo $var0
I love you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo `expr index "$var0" love`    # 获取字符在字符串中的索引位置,返回字符 l 在字符串中的索引位置
3
[ryan@ryan-tencentcloud-1 ~]$ echo `expr index "$var0" me`    # 返回字符 e 在子串中的位置
6
[ryan@ryan-tencentcloud-1 ~]$ echo `expr index "$var0" hate`    # 返回字符 e 在子串中的位置
6
1
2
3
4
5
6
7
8
9

# 获取子串长度

语法:expr match $string substr,从头开始匹配,返回子串长度,支持正则表达式。

[ryan@ryan-tencentcloud-1 ~]$ clear
[ryan@ryan-tencentcloud-1 ~]$ var0="I love you, do you love me"
[ryan@ryan-tencentcloud-1 ~]$ echo $var0
I love you, do you love me
[ryan@ryan-tencentcloud-1 ~]$ echo `expr match "$var0" .*me`
26
[ryan@ryan-tencentcloud-1 ~]$ echo `expr match "$var0" .*you`
18
[ryan@ryan-tencentcloud-1 ~]$ echo `expr match "$var0" "I love you"`
10
1
2
3
4
5
6
7
8
9
10

# 抽取字符串中的子串

语法 说明
方法一 ${string:position} 从 string 中的 position 位置开始
方法二 ${string:position:length} 从 string 中的 position 位置开始,匹配长度为 length
方法三 ${string: -position} 从 string 的右边开始匹配
方法四 ${string: (position)} 从 string 的左边开始匹配
方法五 expr substr $string $position $length 从 string 中的 position 位置开始,匹配长度为 length

课程中讲的是:使用 ${string:position} 索引计数从 0 开始,使用 expr substr 索引从 1 开始。但是我实验确实:${string:position:length} 匹配长度为 length,使用 expr substr $string $position $length 匹配长度为 length-1(换了 2 台电脑都是同样结果)。

[ryan@ryan-tencentcloud-1 ~]$ clear
[ryan@ryan-tencentcloud-1 ~]$ var0="Hello World, Hello Ryan"
[ryan@ryan-tencentcloud-1 ~]$ echo $var0
Hello World, Hello Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0:13}"
Hello Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0:6:5}"
World
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0: (-5)}"
 Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0: (5)}"
 World, Hello Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0: (6)}"
World, Hello Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo "${var0: (-10)}"
Hello Ryan
[ryan@ryan-tencentcloud-1 ~]$ echo `expr substr "$var0" 6 5`
Worl
[ryan@ryan-tencentcloud-1 ~]$ echo `expr substr "$var0" 6 6`
World
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 字符串处理练习

# 需求描述

变量 string="Bigdata process framework is Hadoop, Hadoop is an open source project."。执行脚本后打印输出 string 字符串变量,并给出用户以下选项:

  1. 打印 string 长度
  2. 删除字符串中所有的 Hadoop
  3. 替换第一个 Hadoop 为 Mapreduce
  4. 替换全部 Hadoop 为 Mapreduce

用户输入数字 1|2|3|4 ,可以执行对应项功能;输入 q|Q 能退出交互模式。

# 思路分析

  1. 将不同的功能模块划分,编写实现功能函数。

    function print_tips    # 打印提示信息
    function len_of_string    # 打印 string 长度
    function del_hadoop    # 删除字符串中所有的 Hadoop
    function rep_hadoop_mapreduce_first    #替换第一个 Hadoop 为 Mapreduce
    function rep_hadoop_mapreduce_all    #替换全部 Hadoop 为 Mapreduce
    
    1
    2
    3
    4
    5
  2. 程序主流程设计。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

# function print_tips    # 打印提示信息
# function len_of_string    # 打印 string 长度
# function del_hadoop    # 删除字符串中所有的 Hadoop
# function rep_hadoop_mapreduce_first    #替换第一个 Hadoop 为 Mapreduce
# function rep_hadoop_mapreduce_all    #替换全部 Hadoop 为 Mapreduce
#

string="Bigdata process framework is Hadoop, Hadoop is an open source project."

function print_tips() {
    echo && echo -e "
    *******************************************************************
    # 字符串处理练习

    变量 string 为 'Bigdata process framework is Hadoop, Hadoop is an
    open source project.'

            0. 打印 string.
            1. 打印 string 长度.
            2. 删除字符串中所有的 Hadoop.
            3. 替换第一个 Hadoop 为 Mapreduce.
            4. 替换全部 Hadoop 为 Mapreduce.

    *******************************************************************
    " && echo
}

function len_of_string() {
    if [ -n "${string}" ]; then
        echo -e "长度为:${#string}"
    else
        echo -e "字符串为空!"
    fi
}

function del_hadoop() {
    if [ -n "${string}" ]; then
        echo -e "删除字符串中所有的 Hadoop 后:${string//Hadoop/}"
    else
        echo -e "字符串为空!"
    fi
}

function rep_hadoop_mapreduce_first() {
    if [ -n "${string}" ]; then
        echo -e "替换第一个 Hadoop 为 Mapreduce:${string/Hadoop/Mapredue}"
    else
        echo -e "字符串为空!"
    fi
}

function rep_hadoop_mapreduce_all() {
    if [ -n "${string}" ]; then
        echo -e "替换全部 Hadoop 为 Mapreduce:${string//Hadoop/Mapredue}"
    else
        echo -e "字符串为空!"
    fi
}

# print_tips
# len_of_string
# del_hadoop
# rep_hadoop_mapreduce_first
# rep_hadoop_mapreduce_all

while true; do
    # echo -e"[ string=$string ]"
    print_tips
    read -e -p "Pls input your choice (0|1|2|3|4|q|Q)" choice
    case "$choice" in
    0)
        echo "$string"
        ;;
    1)
        len_of_string
        ;;
    2)
        del_hadoop
        ;;
    3)
        rep_hadoop_mapreduce_first
        ;;
    4)
        rep_hadoop_mapreduce_all
        ;;
    q | Q)
        exit
        ;;
    *)
        echo -e "!!! Error, Pls input your choice (0|1|2|3|4|q|Q)"
        ;;
    esac
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

# 命令替换

# 语法

语法
方法一 `command`
方法二 $(command)

# 练习一

# 需求描述

获取系统所有用户并输出。

# 思路分析

  1. 系统所有用户在 /etc/passwd 文件中。
  2. 使用 cut -d ":" -f 1 命令截取输出结果中的第一列。cut 命令默认属于使用 TAB 作为分隔符,使用 -d ":" 命令指定 : 为分隔符。使用 -f 1 参数指定获取第一列。
  3. 使用 (())两个小括号表示算术运算。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

index=0
for user in $(cat /etc/passwd | cut -d ":" -f 1); do
    # echo -e "This is $index user: $user."
    printf "This is %2d user: $user.\n" $index
    index=$(($index + 1))
done
1
2
3
4
5
6
7
8
9
10

# 练习二

# 需求描述

当前日期时间格式化并根据当前时间计算今年和明年年份。

# 思路分析

  1. 使用 TZ='America/Los_Angeles' 命令显示东八区北京时间。
  2. 使用 date 获取当前日期时间。
  3. 使用 %Y-%m-%d %H:%M:%S 或者 %F %T 格式化输出日期时间。
  4. 计算今年和明年年份,使用 (())两个小括号表示算术运算。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

echo && echo -e "Current time: $(TZ='America/Los_Angeles' date "+%Y-%m-%d %H:%M:%S").
Current time: $(TZ='America/Los_Angeles' date "+%F %T").
This is $(date +%Y) year, next year is $(($(date +%Y) + 1)).
" && echo
1
2
3
4
5
6
7
8

# 练习三

# 需求描述

根据系统时间获取今年还剩下多少天/星期,已经过了多少天/星期。

# 思路分析

  1. 使用 date 获取当前日期时间。
  2. 使用 %j 获取今年已经过了多少天,使用 %U (以周日为每星期第一天)、 %V 或者 %W(以周一为每星期第一天)获取今年已经过了多少星期。
  3. 判断当前年份是否为闰年,然后用 365/366 减去已经过的天数就是剩下的天数,再除以 7 就是剩下的星期数。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

if [ $(($(date +%Y) % 4)) -eq 0 -a $(($(date +%Y) % 100)) -ne 0 ]; then
    days=366
elif [ $(($(date +%Y) % 400)) -eq 0 ]; then
    days=366
else
    days=365
fi

echo && echo -e "$(date +%Y) year have $days days.
$(date +%Y) year have passed $(date +%j) days.
$(date +%Y) year have passed $(($(date +%U) - 1)) weeks, with Sunday as first day of week.
$(date +%Y) year have passed $(($(date +%V) - 1)) weeks, with Monday as first day of week.
$(date +%Y) year have passed $(($(date +%W) - 1)) weeks, with Monday as first day of week.
There is $(($days - $(date +%j))) days before $(($(date +%Y) + 1)) year.
There is $((($days - $(date +%j)) / 7)) weeks before $(($(date +%Y) + 1)) year." && echo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 练习四

# 需求分析

判断 nginx 进程是否存在,若不存在则自动拉起该进程。

# 思路分析

  1. 使用 ps -ef | grep nginx | grep -v grep | wc -l 查看 nginx 进程个数,grep -v grep 命令排除 grep 进程, wc -l 命令统计个数。
  2. 当进程个数大于 0 时 nginx 进程存在。否则,nginx 进程不存在,重启 nginx 服务。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)
if [ $nginx_process_num -ne 0 ]; then
    echo -e "nginx 进程存在!"
else
    echo -e "nginx 进程不存在!" && sudo systemctl start nginx
fi
1
2
3
4
5
6
7
8
9
10

# 有类型变量

  • declare 命令和 typeset 命令两者等价;
  • declare 命令、 typeset 命令都是用来定义变量类型的;
参数 含义
-r 将变量定义为只读
-i 将变量定义为整数
-a 将变量定义为数组
-f 显示系统定义过的所有函数名及函数体
-F 显示系统定义过的函数名
-x 将变量声明定义为环境变量,可供 shell 以外的程序来使用。

取消声明的变量:

  • declare +r
  • declare +i
  • declare +a
  • declare +x

# 声明变量为只读类型

  • declare -r 声明变量为只读类型:声明之后不可修改。
[ryan@ryan-tencentcloud-1 ~]$ var1="hello world"
[ryan@ryan-tencentcloud-1 ~]$ echo $var1
hello world
[ryan@ryan-tencentcloud-1 ~]$ var1="hello ryan"
[ryan@ryan-tencentcloud-1 ~]$ echo $var1
hello ryan
[ryan@ryan-tencentcloud-1 ~]$ declare -r var1="hello world"
[ryan@ryan-tencentcloud-1 ~]$ var1="hello ryan"
zsh: read-only variable: var1
1
2
3
4
5
6
7
8
9

# 声明变量为整数类型

  • declare -i 声明变量为整数类型,可以算术运算。
[ryan@ryan-tencentcloud-1 ~]$ num1=10
[ryan@ryan-tencentcloud-1 ~]$ num2=$num1+10
[ryan@ryan-tencentcloud-1 ~]$ echo $num2
10+10
[ryan@ryan-tencentcloud-1 ~]$ echo $(($num1 + 10)) #作为整数类型进行算术运算
20
[ryan@ryan-tencentcloud-1 ~]$ expr $num1 + 10
20
[ryan@ryan-tencentcloud-1 ~]$ declare -i num3=$num1+10
[ryan@ryan-tencentcloud-1 ~]$ echo $num3
20
1
2
3
4
5
6
7
8
9
10
11

# 显示系统定义过的函数名及函数体

  • declare -f 显示系统定义过的所有函数名及函数体。
  • declare -F 显示系统定义过的函数名。
## declare -f 显示系统定义过的所有函数名及函数体
[ryan@ryan-tencentcloud-1 ~]$ declare -f

## declare -F 显示系统定义过的函数名
[ryan@ryan-tencentcloud-1 ~]$ declare -F
1
2
3
4
5

# 声明变量类型为数组

  • declare -a 声明变量类型为数组,数组下标索引从 1 开始。
#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

declare -a array
array=("letme" "zztai1" "mlxg" "karsa" "xiaohu" "xiye" "uzi" "meiko" "ming")

function printf_array() {
    index=1
    for user in ${array[@]}; do
        # echo -e "    - This is $index user: $user."
        printf "    - This is %2d user: $user.\n" $index
        index=$((($index + 1)))
    done
}

echo -e "打印数组的所有元素: ${array[@]}"
echo -e "数组下标索引为 1 的元素: ${array[1]}"
echo -e "数组下标索引为 2 的元素: ${array[2]}"
echo -e "数组下标索引为 6 的元素: ${array[6]}"
echo -e "数组下标索引为 8 的元素: ${array[8]}"
echo -e "数组长度: ${#array[@]}"
echo -e "数组第 6 个元素 ${array[6]} 长度: ${#array[6]}"
echo -e "数组第 8 个元素 ${array[8]} 长度: ${#array[8]}"
echo -e "循环遍历数组打印元素: " && printf_array
echo -e "---------------------"
echo -e "给数组下标索引为 10 的元素赋值 Firefox: " && array[10]="FireFox"
echo -e "数组下标索引为 10 的元素: ${array[10]}"
echo -e "给数组下标索引为 11 的元素赋值 Heart: " && array[11]="Heart"
echo -e "数组下标索引为 11 的元素: ${array[11]}"
echo -e "给数组下标索引为 13 的元素赋值 Dog8: " && array[13]="Dog8"
echo -e "数组下标索引为 13 的元素: ${array[13]}"
echo -e "新数组长度: ${#array[@]}"
echo -e "循环遍历新数组打印元素: " && printf_array
echo -e "---------------------"
echo -e "打印数组中第 1 - 9 的元素: ${array[@]:0:8}"
echo -e "删除数组中第 12 个元素:" && unset array[12]
echo -e "数组下标索引为 12 的元素: ${array[12]}"
echo -e "新数组长度: ${#array[@]}"
echo -e "循环遍历新数组打印元素: " && printf_array
echo -e "---------------------"
echo -e "将数组中元素值包含 FireFox 的替换为 阿布: ${array[@]/FireFox/阿布}"
echo -e "数组下标索引为 10 的元素: ${array[10]}"
echo -e "新数组长度: ${#array[@]}"
echo -e "循环遍历新数组打印元素: " && printf_array
echo -e "---------------------"
echo -e "清空数组: " && unset array
echo -e "新数组长度: ${#array[@]}"
echo -e "循环遍历新数组打印元素: " && printf_array
echo -e "---------------------"

# Output
#
# 打印数组的所有元素: letme zztai1 mlxg karsa xiaohu xiye uzi meiko ming
# 数组下标索引为 1 的元素: zztai1
# 数组下标索引为 2 的元素: mlxg
# 数组下标索引为 6 的元素: uzi
# 数组下标索引为 8 的元素: ming
# 数组长度: 9
# 数组第 6 个元素 uzi 长度: 3
# 数组第 8 个元素 ming 长度: 4
# 循环遍历数组打印元素:
#     - This is  1 user: letme.
#     - This is  2 user: zztai1.
#     - This is  3 user: mlxg.
#     - This is  4 user: karsa.
#     - This is  5 user: xiaohu.
#     - This is  6 user: xiye.
#     - This is  7 user: uzi.
#     - This is  8 user: meiko.
#     - This is  9 user: ming.
# ---------------------
# 给数组下标索引为 10 的元素赋值 Firefox:
# 数组下标索引为 10 的元素: FireFox
# 给数组下标索引为 11 的元素赋值 Heart:
# 数组下标索引为 11 的元素: Heart
# 给数组下标索引为 13 的元素赋值 Dog8:
# 数组下标索引为 13 的元素: Dog8
# 新数组长度: 12
# 循环遍历新数组打印元素:
#     - This is  1 user: letme.
#     - This is  2 user: zztai1.
#     - This is  3 user: mlxg.
#     - This is  4 user: karsa.
#     - This is  5 user: xiaohu.
#     - This is  6 user: xiye.
#     - This is  7 user: uzi.
#     - This is  8 user: meiko.
#     - This is  9 user: ming.
#     - This is 10 user: FireFox.
#     - This is 11 user: Heart.
#     - This is 12 user: Dog8.
# ---------------------
# 打印数组中第 1 - 9 的元素: letme zztai1 mlxg karsa xiaohu xiye uzi meiko
# 删除数组中第 12 个元素:
# 数组下标索引为 12 的元素:
# 新数组长度: 12
# 循环遍历新数组打印元素:
#     - This is  1 user: letme.
#     - This is  2 user: zztai1.
#     - This is  3 user: mlxg.
#     - This is  4 user: karsa.
#     - This is  5 user: xiaohu.
#     - This is  6 user: xiye.
#     - This is  7 user: uzi.
#     - This is  8 user: meiko.
#     - This is  9 user: ming.
#     - This is 10 user: FireFox.
#     - This is 11 user: Heart.
#     - This is 12 user: Dog8.
# ---------------------
# 将数组中元素值包含 FireFox 的替换为 阿布: letme zztai1 mlxg karsa xiaohu xiye uzi meiko ming 阿布 Heart Dog8
# 数组下标索引为 10 的元素: FireFox
# 新数组长度: 12
# 循环遍历新数组打印元素:
#     - This is  1 user: letme.
#     - This is  2 user: zztai1.
#     - This is  3 user: mlxg.
#     - This is  4 user: karsa.
#     - This is  5 user: xiaohu.
#     - This is  6 user: xiye.
#     - This is  7 user: uzi.
#     - This is  8 user: meiko.
#     - This is  9 user: ming.
#     - This is 10 user: FireFox.
#     - This is 11 user: Heart.
#     - This is 12 user: Dog8.
# ---------------------
# 清空数组:
# 新数组长度: 0
# 循环遍历新数组打印元素:
# ---------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

# 声明变量为环境变量

  • declear -x 声明变量为环境变量,可供 shell 以外的程序来使用。

# 数学运算 expr

# 语法

语法
方法一 expr $num1 operator $num2
方法二 $(($num1 operator $num2))

# 操作符对照表

操作符 含义
num1 | num2 num1 不为空且非 0,返回 num1;否则返回 num2
num1 & num2 num1 不为 i 空且非 0,返回 num1;否则返回 0
num1 < num2 num1 小于 num2,返回 1;否则返回 0
num1 <= num2 num1 小于等于 num2,返回 1;否则返回 0
num1 = num2 num1 等于 num2,返回 1;否则返回 0
num1 != num2 num1 不等于 num2,返回 1;否则返回 0
num1 > num2 num1 大于 num2,返回 1;否则返回 0
num1 >= num2 num1 大于等于 num2,返回 1;否则返回 0
num1 + num2 num1 num2 求和
num1 - num2 num1 num2 求差
num1 * num2 num1 num2 求积
num1 / num2 num1 num2 求商
num1 % num2 num1 num2 求余
#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
set -x

declare +i num0 num1 num2 num3 num4
declare -i num0=56 num1=78 num2=34 num3=90 num4=12

expr $num0 \| $num3
expr $num1 \& $num2
expr $num0 \< $num2
expr $num0 \<= $num3
expr $num0 \> $num1
expr $num1 \>= $num2
expr $num2 = $num3
expr $num4 != $num3
expr $num1 + $num1
expr $num1 - $num2
expr $num1 \* $num3
expr $num1 / $num4
expr $num2 % $num4

declare +i num0 num1 num2 num3 num4

# Output
#
# + declare +i num0 num1 num2 num3 num4
# + declare -i num0=56 num1=78 num2=34 num3=90 num4=12
# + expr 56 '|' 90
# 56
# + expr 78 '&' 34
# 78
# + expr 56 '<' 34
# 0
# + expr 56 '<=' 90
# 1
# + expr 56 '>' 78
# 0
# + expr 78 '>=' 34
# 1
# + expr 34 = 90
# 0
# + expr 12 '!=' 90
# 1
# + expr 78 + 78
# 156
# + expr 78 - 34
# 44
# + expr 78 '*' 90
# 7020
# + expr 78 / 12
# 6
# + expr 34 % 12
# 10
# + declare +i num0 num1 num2 num3 num4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 练习

# 需求描述

提示用户输入一个正整数 num,然后计算 1+2+3+...+num 的值。要求必须对 num 是否为正整数做判断,不符合应当允许再次输入。

# 思路分析

  1. 求和
    • 使用公式 n(a1+an)/2 求和;
    • 使用 seq -s+ 求和;
    • 使用循环求和;
  2. 对 num 是否为整数进行判断:使用命令 expr $num + 0进行求和运算,对命令结果进行判断 "$?" -eq 0 。求和运算要求 num 为整数。如果是浮点数会报错 expr: non-integer argument。 命令执行不成功会返回一个非 0 的整数。
  3. 对 num 是否为正数进行判断:num > 0。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

Green_font_prefix="\033[32m" && Red_font_prefix="\033[31m" && Green_background_prefix="\033[42;37m" && Red_background_prefix="\033[41;37m" && Font_color_suffix="\033[0m"

while true; do
    read -p "Pls input a positive number: " num
    expr ${num} + 1 &>/dev/null # 屏蔽运算结果
    # if [ $? -eq 0 -a `expr ${num} \> 0` -eq 1 ]; then
    if [ $? -eq 0 -a ${num} -gt 0 ] &>/dev/null; then
        # 使用求和公式计算
        a1=1 && an=${num} && n=${num}
        echo -e "\n - 使用求和公式计算:  1+2+3+...+${num} = $(((${a1} + ${an}) * ${n} / 2))."

        # 使用 seq -s+ 计算
        echo -e " - 使用 seq -s+ 计算: 1+2+3+...+${num} = $(($(seq -s+ 1 ${num})))."

        # 使用循环计算
        sum=0
        for ((i = 1; i <= ${num}; i++)); do
            sum=$(($sum + $i))
        done
        echo -e " - 使用循环计算:      1+2+3+...+${num} = ${sum}.\n"
    else
        echo -e "\n${Red_font_prefix}ERROR!!!${Font_color_suffix} Pls input a positive number! \n"
        continue
    fi
done

# Output
#
# Pls input a positive number: 0
#
# ERROR!!! Pls input a positive number!
#
# Pls input a positive number: 20
#
#  - 使用求和公式计算:  1+2+3+...+20 = 210.
#  - 使用 seq -s+ 计算: 1+2+3+...+20 = 210.
#  - 使用循环计算:      1+2+3+...+20 = 210.
#
# Pls input a positive number: 2a25
#
# ERROR!!! Pls input a positive number!
#
# Pls input a positive number: 100
#
#  - 使用求和公式计算:  1+2+3+...+100 = 5050.
#  - 使用 seq -s+ 计算: 1+2+3+...+100 = 5050.
#  - 使用循环计算:      1+2+3+...+100 = 5050.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 数学运算 bc

  • bc 是 bash 内建的运算器,支持浮点数运算;
  • 内建变量 scale 可以设置计算结果精度,默认为 0。

# 语法

语法
echo "$num1 operator $num2" \| bc

# 操作符对照表

操作符 含义
num1 + num2 求和运算
num1 - num2 求差运算
num1 * num2 求积运算
num1 / num2 求商运算
num1 % num2 求余运算
num1 ^ num2 指数运算

# 练习

# 需求描述

提示用户输入数和一个操作符,然后对其进行数学运算。要求:除法运算时计算结果需要精确到 6 位。

# 思路分析

  1. 数学运算使用 bc 处理;
  2. 除法运算精确度使用 scale 控制。

# 脚本编写

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

Green_font_prefix="\033[32m" && Red_font_prefix="\033[31m" && Green_background_prefix="\033[42;37m" && Red_background_prefix="\033[41;37m" && Font_color_suffix="\033[0m"

while true; do
    read -e -p "Pls input two positive number and a operator (+|-|*|/|%) : " num1 num2 ope
    case "${ope}" in
    +)
        echo -e "${num1} + ${num2}" | bc
        ;;
    -)
        echo -e "${num1} - ${num2}" | bc
        ;;
    \*)
        echo -e "${num1} * ${num2}" | bc
        ;;
    /)
        echo -e "scale=6;${num1} / ${num2}" | bc
        ;;
    %)
        echo -e "${num1} % ${num2}" | bc
        ;;
    *)
        echo -e "${Red_font_prefix}ERROR!!!${Font_color_suffix} Pls input a operator (+|-|*|/|%)!\n "
        ;;
    esac
done

# Output
#
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 u
# ERROR!!! Pls input a operator (+|-|*|/|%)!
#
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 +
# 23
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 -
# 17
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 *
# 60
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 /
# 6.666666
# Pls input two positive number and a operator (+|-|*|/|%) : 20 3 %
# 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

本文代码:02-shell (opens new window)

目录
函数的高级用法

← 目录 函数的高级用法→

Theme by Vdoing | Copyright © 2020-2022 JaimeZeng | ❤️ | CC BY-NC-SA 4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式