Shell脚本:Linux Shell脚本学习指南(第二部分Shell编程)三

news2024/11/29 10:53:09

第二部分:Shell编程(三)

二十一、Shell declare和typeset命令:设置变量属性

declare 和 typeset 都是 Shell 内建命令,它们的用法相同,都用来设置变量的属性。不过 typeset 已经被弃用了,建议使用 declare 代替。

declare 命令的用法如下所示:

declare [+/-] [aAfFgilprtux] [变量名=变量值]

其中,-表示设置属性,+表示取消属性,aAfFgilprtux都是具体的选项,它们的含义如下表所示:

选项含义
-f [name]列出之前由用户在脚本中定义的函数名称和函数体。
-F [name]仅列出自定义函数名称。
-g name在 Shell 函数内部创建全局变量。
-p [name]显示指定变量的属性和值。
-a name声明变量为普通数组。
-A name声明变量为关联数组(支持索引下标为字符串)。
-i name 将变量定义为整数型。
-r name[=value] 将变量定义为只读(不可修改和删除),等价于 readonly name。
-x name[=value]将变量设置为环境变量,等价于 export name[=value]。

【实例1】将变量声明为整数并进行计算。

#!/bin/bash

declare -i m n ret          #将多个变量声明为整数

m=10

n=30

ret=$m+$n

echo $ret

运行结果:

40

【实例2】将变量定义为只读变量。

[c.biancheng.net]$ declare -r n=10

[c.biancheng.net]$ n=20

bash: n: 只读变量

[c.biancheng.net]$ echo $n

10

【实例3】显示变量的属性和值。

[c.biancheng.net]$ declare -r n=10

[c.biancheng.net]$ declare -p n

declare -r n="10"

二十二、Shell数学计算(算术运算,加减乘除运算)

如果要执行算术运算(数学计算),就离不开各种运算符号,和其他编程语言类似,Shell 也有很多算术运算符,下面就给大家介绍一下常见的 Shell 算术运算符,如下表所示。

Shell 算术运算符一览表

算术运算符说明/含义
+、-加法(或正号)、减法(或负号)
*、/、%乘法、除法、取余(取模)
**幂运算
++、--自增和自减,可以放在变量的前面也可以放在变量的后面
!、&&、||逻辑非(取反)、逻辑与(and)、逻辑或(or)
<、<=、>、>=比较符号(小于、小于等于、大于、大于等于)
==、!=、=比较符号(相等、不相等;对于字符串,= 也可以表示相当于)
<<、>>向左移位、向右移位
~、|、 &、^按位取反、按位或、按位与、按位异或
=、+=、-=、*=、/=、%=赋值运算符,例如 a+=1 相当于 a=a+1,a-=1 相当于 a=a-1

但是,Shell 和其它编程语言不同,Shell 不能直接进行算数运算,必须使用数学计算命令,这让初学者感觉很困惑,也让有经验的程序员感觉很奇葩。

下面我们先来看一个反面的例子:

[c.biancheng.net]$ echo 2+8
2+8
[c.biancheng.net]$ a=23
[c.biancheng.net]$ b=$a+55
[c.biancheng.net]$ echo $b
23+55
[c.biancheng.net]$ b=90
[c.biancheng.net]$ c=$a+$b
[c.biancheng.net]$ echo $c
23+90

从上面的运算结果可以看出,默认情况下,Shell 不会直接进行算术运算,而是把+两边的数据(数值或者变量)当做字符串,把+当做字符串连接符,最终的结果是把两个字符串拼接在一起形成一个新的字符串。

这是因为,在 Bash Shell 中,如果不特别指明,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。

换句话说,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。

数学计算命令

要想让数学计算发挥作用,必须使用数学计算命令,Shell 中常用的数学计算命令如下表所示。

Shell 中常用的六种数学计算方式

运算操作符/运算命令说明
(())用于整数运算,效率很高,推荐使用
let用于整数运算,和 (()) 类似。
$[]用于整数运算,不如 (()) 灵活。
expr可用于整数运算,也可以处理字符串。比较麻烦,需要注意各种细节,不推荐使用。
bcLinux下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器。
declare -i将变量定义为整数,然后再进行数学运算时就不会被当做字符串了。功能有限,仅支持最基本的数学运算(加减乘除和取余),不支持逻辑运算、自增自减等,所以在实际开发中很少使用。
如果大家时间有限,只学习 (()) 和 bc 即可,不用学习其它的了: (()) 可以用于整数计算,bc 可以小数计算。

在接下来的章节中,我们将逐一为大家讲解 Shell 中的各种运算符号及运算命令。

二十三、Shell (()):对整数进行数学运算

双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。

注意:(( )) 只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。后续讲到的 bc 命令可以用于小数运算。

1、Shell (( )) 的用法

双小括号 (( )) 的语法格式为:

((表达式))

通俗地讲,就是将数学运算表达式放在(())之间。

表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( )) 命令的执行结果。

可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。

表1:(( )) 的用法

运算操作符/运算命令说明
((a=10+66)
((b=a-15))
((c=a+b))
这种写法可以在计算完成后给变量赋值。以 ((b=a-15)) 为例,即将 a-15 的运算结果赋值给变量 c。

注意,使用变量时不用加$前缀,(( )) 会自动解析变量名。
a=$((10+66)
b=$((a-15))
c=$((a+b))
可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。

注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。
((a>7 && b==c))(( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。
echo $((a+10))需要立即输出表达式的运算结果时,可以在 (( )) 前面加$符号。
((a=3+5, b=a+10))对多个表达式同时进行计算。

在 (( )) 中使用变量无需加上$前缀,(( )) 会自动解析变量名,这使得代码更加简洁,也符合程序员的书写习惯。

2、Shell (( )) 实例演示

【实例1】利用 (( )) 进行简单的数值计算。

[c.biancheng.net]$ echo $((1+1))

2

[c.biancheng.net]$ echo $((6-3))

3

[c.biancheng.net]$ i=5

[c.biancheng.net]$ ((i=i*2))             #可以简写为 ((i*=2))。

[c.biancheng.net]$ echo $i             #使用 echo 输出变量结果时要加 $。

10

【实例2】用 (( )) 进行稍微复杂一些的综合算术运算。

[c.biancheng.net]$ ((a=1+2**3-4%3))

[c.biancheng.net]$ echo $a

8

[c.biancheng.net]$ b=$((1+2**3-4%3)) #运算后将结果赋值给变量,变量放在了括号的外面。

[c.biancheng.net]$ echo $b

8

[c.biancheng.net]$ echo $((1+2**3-4%3)) #也可以直接将表达式的结果输出,注意不要丢掉 $ 符号。

8

[c.biancheng.net]$ a=$((100*(100+1)/2)) #利用公式计算1+2+3+...+100的和。 [c.biancheng.net]$ echo $a

5050

[c.biancheng.net]$ echo $((100*(100+1)/2)) #也可以直接输出表达式的结果。

5050

【实例3】利用 (( )) 进行逻辑运算。

[c.biancheng.net]$ echo $((3<8)) #3<8 的结果是成立的,因此,输出了 1,1 表示真

1

[c.biancheng.net]$ echo $((8<3)) #8<3 的结果是不成立的,因此,输出了 0,0 表示假。

0

[c.biancheng.net]$ echo $((8==8)) #判断是否相等。

1

[c.biancheng.net]$ if ((8>7&&5==5))

> then

> echo yes

> fi

yes

最后是一个简单的 if 语句的格式,它的意思是,如果 8>7 成立,并且 5==5 成立,那么输出 yes。显然,这两个条件都是成立的,所以输出了 yes。

【实例4】利用 (( )) 进行自增(++)和自减(--)运算。

[c.biancheng.net]$ a=10

[c.biancheng.net]$ echo $((a++)) #如果++在a的后面,那么在输出整个表达式时,会输出a的值,因为a为10,所以表达式的值为10。

10

[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a++,因此a会自增1,因此输出a的值为11。

11

[c.biancheng.net]$ a=11

[c.biancheng.net]$ echo $((a--)) #如果--在a的后面,那么在输出整个表达式时,会输出a的值,因为a为11,所以表达式的值的为11。

11

[c.biancheng.net]$ echo $a #执行上面的表达式后,因为有a--,因此a会自动减1,因此a为10。

10

[c.biancheng.net]$ a=10

[c.biancheng.net]$ echo $((--a)) #如果--在a的前面,那么在输出整个表达式时,先进行自增或自减计算,因为a为10,且要自减,所以表达式的值为9。

9

[c.biancheng.net]$ echo $a #执行上面的表达式后,a自减1,因此a为9。

9

[c.biancheng.net]$ echo $((++a)) #如果++在a的前面,输出整个表达式时,先进行自增或自减计算,因为a为9,且要自增1,所以输出10。 10 [c.biancheng.net]$ echo $a #执行上面的表达式后,a自增1,因此a为10。

10

本教程假设读者具备基本的编程能力,相信读者对于前自增(前自减)和后自增(后自减)的区别也非常清楚,这里就不再赘述,只进行简单的说明:

  • 执行 echo $((a++)) 和 echo $((a--)) 命令输出整个表达式时,输出的值即为 a 的值,表达式执行完毕后,会再对 a 进行 ++、-- 的运算;
  • 而执行 echo $((++a)) 和 echo $((--a)) 命令输出整个表达式时,会先对 a 进行 ++、-- 的运算,然后再输出表达式的值,即为 a 运算后的值。

【实例5】利用 (( )) 同时对多个表达式进行计算。

[c.biancheng.net]$ ((a=3+5, b=a+10)) #先计算第一个表达式,再计算第二个表达式 [c.biancheng.net]$ echo $a $b

8 18

[c.biancheng.net]$ c=$((4+8, a+b)) #以最后一个表达式的结果作为整个(())命令的执行结果 [c.biancheng.net]$ echo $c

26

二十四、Shell let命令:对整数进行数学运算

let 命令和双小括号 (( )) 的用法是类似的,它们都是用来对整数进行运算

注意:和双小括号 (( )) 一样,let 命令也只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。

Shell let 命令的语法格式为:

let 表达式

或者

let "表达式"

或者

let '表达式'

它们都等价于((表达式))

当表达式中含有 Shell 特殊字符(例如 |)时,需要用双引号" "或者单引号' '将表达式包围起来。

和 (( )) 类似,let 命令也支持一次性计算多个表达式,并且以最后一个表达式的值作为整个 let 命令的执行结果。但是,对于多个表达式之间的分隔符,let 和 (( )) 是有区别的:

  • let 命令以空格来分隔多个表达式;
  • (( )) 以逗号,来分隔多个表达式。

另外还要注意,对于类似let x+y这样的写法,Shell 虽然计算了 x+y 的值,但却将结果丢弃;若不想这样,可以使用let sum=x+y将 x+y 的结果保存在变量 sum 中。

这种情况下 (( )) 显然更加灵活,可以使用$((x+y))来获取 x+y 的结果。请看下面的例子:

[c.biancheng.net]$ a=10 b=20

[c.biancheng.net]$ echo $((a+b))

30

[c.biancheng.net]$ echo let a+b #错误,echo会把 let a+b作为一个字符串输出

let a+b

Shell let 命令实例演示

【实例1】给变量 i 加 8:

[c.biancheng.net]$ i=2

[c.biancheng.net]$ let i+=8

[c.biancheng.net]$ echo $i

10

let i+=8 等同于 ((i+=8)),但后者效率更高。

【实例2】let 后面可以跟多个表达式。

[c.biancheng.net]$ a=10 b=35

[c.biancheng.net]$ let a+=6 c=a+b #多个表达式以空格为分隔

[c.biancheng.net]$ echo $a $c

16 51

二十五、Shell $[]:对整数进行数学运算

和 (())、let 命令类似,$[] 也只能进行整数运算

Shell $[] 的用法如下:

$[表达式]

$[] 会对表达式进行计算,并取得计算结果。如果表达式中包含了变量,那么你可以加$,也可以不加。

Shell $[] 举例:

[c.biancheng.net]$ echo $[3*5] #直接输出结算结果

15

[c.biancheng.net]$ echo $[(3+4)*5] #使用()

35

[c.biancheng.net]$ n=6

[c.biancheng.net]$ m=$[n*2] #将计算结果赋值给变量

[c.biancheng.net]$ echo $[m+n]

18

[c.biancheng.net]$ echo $[$m*$n] #在变量前边加$也是可以的

72

[c.biancheng.net]$ echo $[4*(m+n)]

72

需要注意的是,不能单独使用 $[],必须能够接收 $[] 的计算结果。例如,下面的用法是错误的:

[c.biancheng.net]$ $[3+4]

bash: 7: 未找到命令...

[c.biancheng.net]$ $[m+3]

bash: 15: 未找到命令...

二十六、Shell expr命令:对整数进行运算

expr 是 evaluate expressions 的缩写,译为“表达式求值”。Shell expr 是一个功能强大,并且比较复杂的命令,它除了可以实现整数计算,还可以结合一些选项对字符串进行处理,例如计算字符串长度、字符串比较、字符串匹配、字符串提取等。

本节只讲解 expr 在整数计算方面的应用,并不涉及字符串处理,有兴趣的读者请自行研究。

Shell expr 对于整数计算的用法为:

expr 表达式

expr 对表达式的格式有几点特殊的要求:

  • 出现在表达式中的运算符、数字、变量和小括号的左右两边至少要有一个空格,否则会报错。
  • 有些特殊符号必须用反斜杠\进行转义(屏蔽其特殊含义),比如乘号*和小括号(),如果不用\转义,那么 Shell 会把它们误解为正则表达式中的符号(*对应通配符,()对应分组)。
  • 使用变量时要加$前缀

【实例1】expr 整数计算简单举例:

[c.biancheng.net]$ expr 2 +3 #错误:加号和 3 之前没有空格

expr: 语法错误

[c.biancheng.net]$ expr 2 + 3 #这样才是正确的

5

[c.biancheng.net]$ expr 4 * 5 #错误:乘号没有转义

expr: 语法错误

[c.biancheng.net]$ expr 4 \* 5 #使用 \ 转义后才是正确的

20

[c.biancheng.net]$ expr ( 2 + 3 ) \* 4 #小括号也需要转义

bash: 未预期的符号 `2' 附近有语法错误

[c.biancheng.net]$ expr \( 2 + 3 \) \* 4 #使用 \ 转义后才是正确的

20

[c.biancheng.net]$ n=3

[c.biancheng.net]$ expr n + 2 #使用变量时要加 $

expr: 非整数参数

[c.biancheng.net]$ expr $n + 2 #加上 $ 才是正确的

5

[c.biancheng.net]$ m=7

[c.biancheng.net]$ expr $m \* \( $n + 5 \)

56

以上是直接使用 expr 命令,计算结果会直接输出,如果你希望将计算结果赋值给变量,那么需要将整个表达式用反引号``(位于 Tab 键的上方)包围起来,请看下面的例子。

【实例2】将 expr 的计算结果赋值给变量:

[c.biancheng.net]$ m=5

[c.biancheng.net]$ n=`expr $m + 10`

[c.biancheng.net]$ echo $n

15

你看,使用 expr 进行数学计算是多么的麻烦呀,需要注意各种细节,我奉劝大家还是省省心,老老实实用 (())、let 或者 $[] 吧。

二十七、Linux bc命令:一款数学计算器

Bash Shell 内置了对整数运算的支持,但是并不支持浮点运算,而 Linux bc 命令可以很方便的进行浮点运算,当然整数运算也不再话下。

bc 甚至可以称得上是一种编程语言了,它支持变量、数组、输入输出、分支结构、循环结构、函数等基本的编程元素,所以 Linux 手册中是这样来描述 bc 的:

An arbitrary precision calculator language

翻译过来就是“一个任意精度的计算器语言”。

在终端输入bc命令,然后回车即可进入 bc 进行交互式的数学计算。在 Shell 编程中,我们也可以通过管道和输入重定向来使用 bc。

本节我们先学习如何在交互式环境下使用 bc,然后再学习如何在 Shell 编程中使用 bc,这样就易如反掌了。

1、从终端进入 bc

在终端输入 bc 命令,然后回车,就可以进入 bc,请看下图:

进入bc

bc 命令还有一些选项,可能你会用到,请看下表。

选项说明
-h | --help帮助信息
-v | --version显示命令版本信息
-l | --mathlib使用标准数学库
-i | --interactive强制交互
-w | --warn显示 POSIX 的警告信息
-s | --standard使用 POSIX 标准来处理
-q | --quiet不显示欢迎信息

例如你不想输入 bc 命令后显示一堆没用的信息,那么可以输入bc -q

输入bc -q命令

2、在交互式环境下使用 bc

使用 bc 进行数学计算是非常容易的,像平常一样输入数学表达式,然后按下回车键就可以看到结果,请看下图。

使用bc进行数学计算

值得一提的是,我们定义了一个变量 n,然后在计算中也使用了 n,可见 bc 是支持变量的。

除了变量,bc 还支持函数、循环结构、分支结构等常见的编程元素,它们和其它编程语言的语法类似。下面我们定义一个求阶乘的函数:

在bc中定义函数

其实我们很少使用这么复杂的功能,大部分情况下还是把 bc 作为普通的数学计算器,求一下表达式的值而已,所以大家不必深究,了解一下即可。

(1)内置变量

bc 有四个内置变量,我们在计算时会经常用到,如下表所示:

变量名作 用
scale指定精度,也即小数点后的位数;默认为 0,也即不使用小数部分。
ibase指定输入的数字的进制,默认为十进制。
obase指定输出的数字的进制,默认为十进制。
last 或者 .表示最近打印的数字

【实例1】scale 变量用法举例:

scale变量的用法举例

刚开始的时候,10/3 的值为 3,不带小数部分,就是因为 scale 变量的默认值为 0;后边给 scale 指定了一个大于 0 的值,就能看到小数部分了

【实例2】ibase 和 obase 变量用法举例:

ibase 和 obase 用法示例

注意:obase 要尽量放在 ibase 前面,因为 ibase 设置后,后面的数字都是以 ibase 的进制来换算的。

(2)内置函数

除了内置变量,bc 还有一些内置函数,如下表所示:

函数名作用
s(x)计算 x 的正弦值,x 是弧度值。
c(x)计算 x 的余弦值,x 是弧度值。
a(x)计算 x 的反正切值,返回弧度值。
l(x)计算 x 的自然对数。
e(x)求 e 的 x 次方。
j(n, x)贝塞尔函数,计算从 n 到 x 的阶数。

要想使用这些数学函数,在输入 bc 命令时需要使用-l选项,表示启用数学库。请看下面的例子:

在 bc 中使用数学函数

(3)在一行中使用多个表达式

在前边的例子中,我们基本上是一行一个表达式,这样看起来更加舒服;如果你愿意,也可以将多个表达式放在一行,只要用分号;隔开就行。请看下面的例子:

在一行中使用多个表达式

3、在 Shell 中使用 bc 计算器

在 Shell 脚本中,我们可以借助管道或者输入重定向来使用 bc 计算器。

  • 管道是 Linux 进程间的一种通信机制,它可以将前一个命令(进程)的输出作为下一个命令(进程)的输入,两个命令之间使用竖线|分隔
  • 通常情况下,一个命令从终端获得用户输入的内容,如果让它从其他地方(比如文件)获得输入,那么就需要重定向。

此处我们并不打算展开讲解管道和重定向,不了解的小伙伴请自行百度。

(1)借助管道使用 bc 计算器

如果读者希望直接输出 bc 的计算结果,那么可以使用下面的形式:

echo "expression" | bc

expression就是希望计算的数学表达式,它必须符合 bc 的语法,上面我们已经进行了介绍。在 expression 中,还可以使用 Shell 脚本中的变量。

使用下面的形式可以将 bc 的计算结果赋值给 Shell 变量:

variable=$(echo "expression" | bc)

variable 就是变量名。

【实例1】最简单的形式:

[c.biancheng.net]$ echo "3*8"|bc

24

[c.biancheng.net]$ ret=$(echo "4+9"|bc)

[c.biancheng.net]$ echo $ret

13

【实例2】使用 bc 中的变量:

[c.biancheng.net]$ echo "scale=4;3*8/7"|bc

3.4285

[c.biancheng.net]$ echo "scale=4;3*8/7;last*5"|bc

3.4285 17.1425

【实例3】使用 Shell 脚本中的变量:

[c.biancheng.net]$ x=4

[c.biancheng.net]$ echo "scale=5;n=$x+2;e(n)"|bc -l

403.42879

在第二条命令中,$x表示使用第一条 Shell 命令中定义的变量,n是在 bc 中定义的新变量,它和 Shell 脚本是没关系的。

【实例4】进制转换:

#十进制转十六进制

[mozhiyan@localhost ~]$ m=31

[mozhiyan@localhost ~]$ n=$(echo "obase=16;$m"|bc)

[mozhiyan@localhost ~]$ echo $n 1F #十六进制转十进制

[mozhiyan@localhost ~]$ m=1E

[mozhiyan@localhost ~]$ n=$(echo "obase=10;ibase=16;$m"|bc)

[mozhiyan@localhost ~]$ echo $n

30

(2)借助输入重定向使用 bc 计算器

可以使用下面的形式将 bc 的计算结果赋值给 Shell 变量:

variable=$(bc << EOF
expressions
EOF
)

其中,variable是 Shell 变量名,express是要计算的数学表达式(可以换行,和进入 bc 以后的书写形式一样),EOF是数学表达式的开始和结束标识(你也可以换成其它的名字,比如 aaa、bbb 等)。

请看下面的例子:

[c.biancheng.net]$ m=1E

[c.biancheng.net]$ n=$(bc << EOF

> obase=10;

> ibase=16;

> print $m

> EOF

> )

[c.biancheng.net]$ echo $n

30

如果你有大量的数学计算,那么使用输入重定向就比较方便,因为数学表达式可以换行,写起来更加清晰明了。

二十八、Shell declare -i:将变量声明为整数类型

《二十一、Shell declare和typeset命令:设置变量属性》一节中,我们已经讲解了 declare 命令的各种选项,为了让 Shell 进行整数运算,本节我们重点讲解-i选项

默认情况下,Shell 中每一个变量的值都是字符串(不了解的读者请猛击《一、Shell变量》),即使你给变量赋值一个数字,它其实也是字符串,所以在进行数学计算时会出错。

使用 declare 命令的-i选项可以将一个变量声明为整数类型,这样在进行数学计算时就不会作为字符串处理了,请看下面的例子:

#!/bin/bash

declare -i m n ret

m=10

n=30

ret=$m+$n

echo $ret

ret=$n/$m

echo $ret

运行结果:

40
3

除了将 m、n 定义为整数,还必须将 ret 定义为整数,如果不这样做,在执行ret=$m+$nret=$n/$m时,Shell 依然会将 m、n 视为字符串。

此外,你也不能写类似echo $m+$n这样的语句,这种情况下 m、n 也会被视为字符串。

总之,除了将参与运算的变量定义为整数,还得将承载结果的变量定义为整数,而且只能用整数类型的变量来承载运算结果,不能直接使用 echo 输出。

和 (())、let、$[] 不同,declare -i的功能非常有限,仅支持最基本的数学运算(加减乘除和取余),不支持逻辑运算(比较运算、与运算、或运算、非运算),所以在实际开发中很少使用。

二十九、Shell if else语句

和其它编程语言类似,Shell 也支持选择结构,并且有两种形式,分别是 if else 语句和 case in 语句。本节我们先介绍 if else 语句,case in 语句将会在后面介绍。

如果你已经熟悉了C语言、Java、JavaScript等其它编程语言,那么你可能会觉得 Shell 中的 if else 语句有点奇怪。

1、if 语句

最简单的用法就是只使用 if 语句,它的语法格式为:

if  condition
then
        statement(s)
fi

condition是判断条件,如果 condition 成立(返回“真”),那么 then 后边的语句将会被执行;如果 condition 不成立(返回“假”),那么不会执行任何语句。

从本质上讲,if 检测的是命令的退出状态,我们将在下节中深入讲解。

注意,最后必须以fi来闭合,fi 就是 if 倒过来拼写。也正是有了 fi 来结尾,所以即使有多条语句也不需要用{ }包围起来。

如果你喜欢,也可以将 then 和 if 写在一行:

if  condition;  then
        statement(s)
fi

请注意 condition 后边的分号;,当 if 和 then 位于同一行的时候,这个分号是必须的,否则会有语法错误。

(1)实例1

下面的例子使用 if 语句来比较两个数字的大小:

#!/bin/bash

read a

read b

if (( $a == $b ))

then

        echo "a和b相等"

fi

运行结果:

84↙
84↙
a和b相等

《二十三、Shell (()):对整数进行数学运算》一节中我们讲到,(())是一种数学计算命令,它除了可以进行最基本的加减乘除运算,还可以进行大于、小于、等于等关系运算,以及与、或、非逻辑运算。当 a 和 b 相等时,(( $a == $b ))判断条件成立,进入 if,执行 then 后边的 echo 语句。

(2)实例2

在判断条件中也可以使用逻辑运算符,例如:

#!/bin/bash

read age

read iq

if (( $age > 18 && $iq < 60 ))

then

        echo "你都成年了,智商怎么还不及格!"

        echo "来C语言中文网(http://c.biancheng.net/)学习编程吧,能迅速提高你的智商。"

fi

运行结果:

20↙
56↙
你都成年了,智商怎么还不及格!
来C语言中文网(http://c.biancheng.net/)学习编程吧,能迅速提高你的智商。

&&就是逻辑“与”运算符,只有当&&两侧的判断条件都为“真”时,整个判断条件才为“真”。

熟悉其他编程语言的读者请注意,即使 then 后边有多条语句,也不需要用{ }包围起来,因为有 fi 收尾呢。

2、if else 语句

如果有两个分支,就可以使用 if else 语句,它的格式为:

if  condition
then
        statement1
else
        statement2
fi

如果 condition 成立,那么 then 后边的 statement1 语句将会被执行;否则,执行 else 后边的 statement2 语句。

举个例子:

#!/bin/bash

read a

read b

if (( $a == $b ))

then

        echo "a和b相等"

else

        echo "a和b不相等,输入错误"

fi

运行结果:

10↙
20↙
a 和 b 不相等,输入错误

从运行结果可以看出,a 和 b 不相等,判断条件不成立,所以执行了 else 后边的语句。

3、if elif else 语句

Shell 支持任意数目的分支,当分支比较多时,可以使用 if elif else 结构,它的格式为:

if  condition1
then
        statement1
elif condition2
then
        statement2
elif condition3
then
        statement3
……
else
        statementn
fi

注意,if 和 elif 后边都得跟着 then。

整条语句的执行逻辑为:

  • 如果 condition1 成立,那么就执行 if 后边的 statement1;如果 condition1 不成立,那么继续执行 elif,判断 condition2。
  • 如果 condition2 成立,那么就执行 statement2;如果 condition2 不成立,那么继续执行后边的 elif,判断 condition3。
  • 如果 condition3 成立,那么就执行 statement3;如果 condition3 不成立,那么继续执行后边的 elif。
  • 如果所有的 if 和 elif 判断都不成立,就进入最后的 else,执行 statementn。

举个例子,输入年龄,输出对应的人生阶段:

#!/bin/bash

read age

if (( $age <= 2 )); then

        echo "婴儿"

elif (( $age >= 3 && $age <= 8 )); then

        echo "幼儿"

elif (( $age >= 9 && $age <= 17 )); then

        echo "少年"

elif (( $age >= 18 && $age <=25 )); then

        echo "成年"

elif (( $age >= 26 && $age <= 40 )); then

        echo "青年"

elif (( $age >= 41 && $age <= 60 )); then

        echo "中年"

else

        echo "老年"

fi

运行结果1:
19
成年

运行结果2:
100
老年

再举一个例子,输入一个整数,输出该整数对应的星期几的英文表示:

#!/bin/bash

printf "Input integer number: "

read num

if ((num==1)); then

        echo "Monday"

elif ((num==2)); then

        echo "Tuesday"

elif ((num==3)); then

        echo "Wednesday"

elif ((num==4)); then

        echo "Thursday"

elif ((num==5)); then

        echo "Friday"

elif ((num==6)); then

        echo "Saturday"

elif ((num==7)); then

        echo "Sunday"

else

        echo "error"

fi

运行结果1:
Input integer number: 4
Thursday

运行结果2:
Input integer number: 9
error

三十、Shell退出状态

每一条 Shell 命令,不管是 Bash 内置命令(例如 cd、echo),还是外部的 Linux 命令(例如 ls、awk),还是自定义的 Shell 函数,当它退出(运行结束)时,都会返回一个比较小的整数值给调用(使用)它的程序,这就是命令的退出状态(exit statu)

很多 Linux 命令其实就是一个C语言程序,熟悉C语言的读者都知道,main() 函数的最后都有一个 return 0,如果程序想在中间退出,还可以使用 exit 0,这其实就是C语言程序的退出状态。当有其它程序调用这个程序时,就可以捕获这个退出状态。

if 语句的判断条件,从本质上讲,判断的就是命令的退出状态。

按照惯例来说,退出状态为 0 表示“成功”;也就是说,程序执行完成并且没有遇到任何问题。除 0 以外的其它任何退出状态都为“失败”。

之所以说这是“惯例”而非“规定”,是因为也会有例外,比如 diff 命令用来比较两个文件的不同,对于“没有差别”的文件返回 0,对于“找到差别”的文件返回 1,对无效文件名返回 2。

有编程经验的读者请注意,Shell 的这个部分与你所熟悉的其它编程语言正好相反:在C语言、C++、Java、Python中,0 表示“假”,其它值表示“真”。

在 Shell 中,有多种方式取得命令的退出状态,其中《七、$?》是最常见的一种。上节《二十九、Shell if else语句》中使用了(())进行数学计算,我们不妨来看一下它的退出状态。请看下面的代码:

#!/bin/bash

read a

read b

(( $a == $b ));

echo "退出状态:"$?

运行结果1:
26
26
退出状态:0

运行结果2:
17
39
退出状态:1

退出状态和逻辑运算符的组合

Shell if 语句的一个神奇之处是允许我们使用逻辑运算符将多个退出状态组合起来,这样就可以一次判断多个条件了。

Shell 逻辑运算符

运算符使用格式说明
&&expression1 && expression2逻辑与运算符,当 expression1 和 expression2 同时成立时,整个表达式才成立。

如果检测到 expression1 的退出状态为 0,就不会再检测 expression2 了,因为不管 expression2 的退出状态是什么,整个表达式必然都是不成立的,检测了也是多此一举。
||expression1 || expression2逻辑或运算符,expression1 和 expression2 两个表达式中只要有一个成立,整个表达式就成立。

如果检测到 expression1 的退出状态为 1,就不会再检测 expression2 了,因为不管 expression2 的退出状态是什么,整个表达式必然都是成立的,检测了也是多此一举。
!!expression逻辑非运算符,相当于“取反”的效果。如果 expression 成立,那么整个表达式就不成立;如果 expression 不成立,那么整个表达式就成立。

【实例】将用户输入的 URL 写入到文件中。

#!/bin/bash

read filename

read url

if test -w $filename && test -n $url

then

        echo $url > $filename

        echo "写入成功"

else

        echo "写入失败"

fi

在 Shell 脚本文件所在的目录新建一个文本文件并命名为 urls.txt,然后运行 Shell 脚本,运行结果为:

urls.txt↙
http://c.biancheng.net/shell/↙
写入成功

test 是 Shell 内置命令,可以对文件或者字符串进行检测,其中,-w选项用来检测文件是否存在并且可写,-n选项用来检测字符串是否非空。

>表示重定向,默认情况下,echo 向控制台输出,这里我们将输出结果重定向到文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1253923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySql之索引,视图,事务以及存储过程举例详解

一.数据准备 数据准备可参考下面的链接中的数据准备步骤 MySql之内连接&#xff0c;外连接&#xff0c;左连接&#xff0c;右连接以及子查询举例详解-CSDN博客 &#xff08;如有问题可在评论区留言&#xff09; 二.存储过程 1.定义 存储过程 PROCEDURE &#xff0c;也翻译…

Leetcode—167.两数之和 II - 输入有序数组【中等】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—167.两数之和 II - 输入有序数组 实现代码 /*** Note: The returned array must be malloced, assume caller calls free().*/ int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {*returnSiz…

过渡曲线的构造之平面PH曲线

平面PH曲线的构造及其相应性质 平面PH曲线的构造及其相应性质PH曲线理论三次PH曲线的构造及性质四次PH曲线的构造及性质五次PH曲线的构造及性质非尖点五次PH曲线尖点五次PH曲线 参考文献 平面PH曲线的构造及其相应性质 过渡曲线常需要满足在连接点处位置连续、曲率连续以及切线…

Docker Swarm总结+CI/CD Devops、gitlab、sonarqube以及harbor的安装集成配置(3/4)

博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码下载地址&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb;…

makefile编写练习

makefile编写练习 OVERVIEW makefile编写练习文件结构直接编译整个项目并运行将项目制作成为静态库将项目制作成为动态库 编写makefile文件来编译带头文件的程序&#xff0c; 文件结构 初始项目文件结构&#xff0c;如下所示&#xff1a; #ifndef ADD_HPP #define ADD_HPPint…

栈详解(C语言)

文章目录 写在前面1 栈的定义2 栈的初始化3 数据入栈4 数据出栈5 获取栈顶元素6 获取栈元素个数7 判断栈是否为空8 栈的销毁 写在前面 本片文章详细介绍了另外两种存储逻辑关系为 “一对一” 的数据结构——栈和队列中的栈&#xff0c;并使用C语言实现了数组栈。 栈C语言实现源…

Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线(实例分析)

Visual Studio 使用MFC 单文档工程从创建到实现绘制单一颜色直线和绘制渐变颜色的直线 本文主要从零开始创建一个MFC单文档工程然后逐步实现添加按键&#xff08;事件响应函数&#xff09;&#xff0c;最后实现单一颜色直线的绘制与渐变色直线的绘制o(&#xffe3;▽&#xffe…

2、Burp使用

文章目录 一、为Firefox浏览器安装数字证书二、利用Intruder模块进行暴力破解 一、为Firefox浏览器安装数字证书 &#xff08;1&#xff09;利用Firefox浏览器访问http://burp或127.0.0.1:<监听端口>&#xff0c;点击页面右上侧的“CA Certificate”处下载CA证书&#xf…

靡靡之音 天籁之声 ——Adobe Audition

上一期讲到了和Pr配合使用的字幕插件Arctime Pro的相关介绍。相信还记得的小伙伴应该记得我还提到过一个软件叫做Au。 当人们对字幕需求的逐渐满足&#xff0c;我们便开始追求更高层次的享受&#xff0c;当视觉享受在进步&#xff0c;听觉享受想必也不能被落下&#xff01; Au即…

【模板】KMP算法笔记

练习链接&#xff1a;【模板】KMP - 洛谷 题目&#xff1a; 输入 ABABABC ABA 输出 1 3 0 0 1 思路&#xff1a; 根据题意&#xff0c;用到的是KMP算法&#xff0c;KMP算法思想是通过一个一个匹配首字母的原理进行整个匹配效果&#xff0c;当某个首字母不匹配的时候&#x…

【全栈开发】Blitz.js与RedwoodJS

技术的不断发展是必然的。如果你仔细观察这片土地&#xff0c;你会注意到随着技术的成熟而出现的某些模式。特别是&#xff0c;开发人员一直在努力提高性能&#xff0c;简化开发过程&#xff0c;增强开发人员体验。 在本指南中&#xff0c;我们将分析两个帮助全栈应用程序世界…

2023年3月电子学会青少年软件编程 Python编程等级考试一级真题解析(判断题)

2023年3月Python编程等级考试一级真题解析 判断题(共10题,每题2分,共20分) 26、在Python编程中,print的功能是将print()小括号的内容输出到控制台,比如:在Python Shell中输入print(北京,你好)指令,小括号内容可以输出到控制台 答案:错 考点分析:考查python中print…

Proteus仿真--基于PG12864LCD设计的指针式电子钟

本文介绍基于PG12864LCD设计的指针式电子钟&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 本设计中时间芯片选用DS1302芯片&#xff0c;液晶选用PG12864LCD模块&#xff0c;按键K1-K3&#xff0c;K1用于时分选择&#xff0c;K2用于调整功能&#xff0c…

积跬步至千里 || 为循环添加进度条

有时候&#xff0c;我们的Python程序需要运行较长时间&#xff0c;原因是一些环节占用时间太长&#xff08;如for循环&#xff09;。如果我们要观察那些占用时间任务的执行进度&#xff0c;那么有一个进度条能实时的显示任务进度情况的话&#xff0c;将会非常方便。而tqdm库就是…

Docker容器化部署若依微服务ruoyi-cloud项目

系统环境 接下来的内容以 Ubuntu 22.04.1 操作系统为例。 下载安装Docker Ubuntu hihi-IdeaCentre-GeekPro-15ICK:~$ sudo su [sudo] hi 的密码&#xff1a; roothi-IdeaCentre-GeekPro-15ICK:/home/hi# docker ps 找不到命令 “docker”&#xff0c;但可以通过以下软件包安…

JDK、JRE、JVM的特点和关联

Java 的三个重要的概念是 JDK&#xff08;Java Development Kit&#xff09;、JRE&#xff08;Java Runtime Environment&#xff09;和 JVM&#xff08;Java Virtual Machine&#xff09;。它们之间有着密切的关联&#xff0c;同时又有不同的职责和特点。 JDK&#xff08;Java…

使用skforecast进行时间序列预测

时间序列预测是数据科学和商业分析中基于历史数据预测未来价值的一项重要技术。它有着广泛的应用&#xff0c;从需求规划、销售预测到计量经济分析。由于Python的多功能性和专业库的可用性&#xff0c;它已经成为一种流行的预测编程语言。其中一个为时间序列预测任务量身定制的…

【数据库】执行计划中二元操作对一趟扫描算法的应用,理解代价评估的应用和优化,除了磁盘代价还有CPU计算代价不容忽略

二元操作的一趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

makefile项目构建

makefile项目构建 OVERVIEW makefile项目构建1.概念2.make选项3.makefile语法&#xff08;1&#xff09;基本语法&#xff08;2&#xff09;系统与自定变量&#xff08;3&#xff09;常用函数&#xff08;4&#xff09;模式匹配与伪目标 4.makefile编译流程&#xff08;1&#…

机器学习---贝叶斯网络与朴素贝叶斯

1. 贝叶斯法则 如何判定一个人是好人还是坏人&#xff1f; 当你无法准确的熟悉一个事物的本质时&#xff0c;你可以依靠与事物特定本质相关的事件出现的次数来判断 其本质属性的概率。如果你看到一个人总是做一些好事&#xff0c;那这个人就越可能是一个好人。 数学语言表达…