![嵌入式Linux开发技术](https://wfqqreader-1252317822.image.myqcloud.com/cover/138/43738138/b_43738138.jpg)
2.1.5 Shell脚本
2.1.5.1 Shell脚本简介
Shell脚本是指将各类命令预先放在一个文件中,方便一次性执行的程序文件,使用了Linux、UNIX中的命令。Shell提供了数组、循环、条件和逻辑判断等重要功能,使用者可以直接以Shell来写程序,而不必使用类似C语言等传统程序语言的语法。
Shell是一个命令行解释器,按照一定的语法将输入的命令加以解释并传给系统,为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、挂起、停止,甚至编写一些程序。
Shell既是一种命令语言,又是一种程序设计语言。作为程序设计语言,Shell定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,如循环结构和分支结构。作为命令语言,虽然Shell不是Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档,并以并行的方式协调各个程序的运行。
2.1.5.2 创建Shell脚本
打开文本编辑器,新建一个文本文件并命名为test.sh。在test.sh中输入以下代码:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_31_2.jpg?sign=1739582506-rDOl0GF2brWwat6WYzuN9ikDekHlGsfc-0-6645e338a11c06ddc3ab7ad75e34b6f5)
第1行的“#!”是一个约定的标记,告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell;后面的“/bin/bash”指明解释器的位置。
第2行的echo命令用于向标准输出设备(如显示器)输出数据。在.sh文件中使用命令与在终端直接输入命令的效果是一样的。第2行的“#”及其后面的内容是注释。Shell脚本示例如下:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_31_3.jpg?sign=1739582506-oTpSnpCHf1ZIGauR3Mc6RkxAalH5d6Mb-0-c5b4e3e50df3ece2433ed563ea3b6e92)
上述Shell脚本示例的第4行表示从终端读取用户输入的数据,并赋值给PERSON变量。read命令用来从标准输入设备(鼠标、键盘)中读取数据;第5行表示输出PERSON变量的内容,注意在变量名前边要加上“$”,否则会将变量名当成字符串来处理。
2.1.5.3 Shell变量
1)系统变量
Shell的系统变量主要在判断参数和命令返回值时使用,包括脚本和函数的参数,以及脚本和函数的返回值。Shell的系统变量如表2.10所示。
表2.10 Shell的系统变量
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_32_1.jpg?sign=1739582506-9ajNLihbQ4T2gfv6nAcWmAN9PyjtBt1n-0-5be0f540e4ba7f0f34149a5522bf0e55)
2)环境变量
Shell的环境变量是所有Shell程序都可以使用的变量,会影响所有脚本的执行结果。Shell的环境变量如表2.11所示。
表2.11 Shell的环境变量
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_32_2.jpg?sign=1739582506-JkCmPMCJbVWUXhNTqCSOGRsUPt3oR98H-0-fe9c08ffbba8d3902e52ebc9104a291a)
3)设置变量
变量的设置规则如下:
(1)变量名称可以由字母、数字或下画线组成,但不能以数字开头,环境变量名建议大写,便于区分。
(2)变量的默认类型都是字符串型,如果要进行数值运算,则必须指定变量类型为数值型。
(3)变量用等号连接值,等号左右两侧不能有空格。
(4)如果变量的值有空格,则需要使用单引号或者双引号包括。
4)定义变量
Shell支持3种定义变量的方式,例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_33_1.jpg?sign=1739582506-vMt73OFlL5R3WbRB5YD17kdqKUGuEw61-0-d209bc72ff6c000fe3b84ea88126d397)
输出为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_33_2.jpg?sign=1739582506-szP5s4EtXHV77hVFHWjEXo0XYwXDqJK1-0-b2f3f0caa26ccce90cc4690c2a16efe5)
variable是变量名,Stone是赋给变量的值。如果赋给变量的值中不包含空白符,则可以不使用引号;如果赋给变量的值中包含空白符,则必须使用引号包围起来。单引号和双引号是有区别的,当使用单引号包围变量时,单引号里面是什么就输出什么,这种方式适合纯字符串的情况,即不希望解析变量、命令等;当使用双引号包围变量时,输出时会先解析里面的变量和命令,这种方式适合字符串中附带有变量和命令,并且希望解析其中的变量和定义后再输出的变量定义。
5)使用变量
使用一个定义过的变量,只需要在变量名前面加符号“$”即可,例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_33_3.jpg?sign=1739582506-qYhipc80Fl0XBbHzz3ZsaZpXoei3TlL5-0-d26eca90e7aeb3a95945e6d1050f9706)
运行结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_33_4.jpg?sign=1739582506-c3z1a8tcAotJYLHkZjQIPJLO8M9dTTpv-0-968a83453f25ababb57ad58207d16c84)
变量名外面的花括号是可选的,加花括号可以帮助解释器识别变量的边界。
6)修改变量的值
已定义的变量可以重新被赋值,例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_33_5.jpg?sign=1739582506-BfOLrLzx4e9rFZYPA6JUlnhCXqKcEpSP-0-a026678826913611d8a8b2bef857c6ad)
运行结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_1.jpg?sign=1739582506-wavf0zJATLXmjU25zCypGhP6IrBlpxm7-0-9359bb0ae766158a45e930e52233dcb8)
7)删除变量
使用unset命令可以删除变量,例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_2.jpg?sign=1739582506-TwOCEsdf7zWQQavo3qqUvAmcrAuJ6qjd-0-ae8e952151d9380a8098bee08a38d79f)
变量被删除后不能再次使用;unset命令不能删除只读变量。
2.1.5.4 Shell的流程控制
(1)if语句。if语句的格式为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_3.jpg?sign=1739582506-1660RYj9nQxtWNAHexIATfH7O4R31VV3-0-1bd400bac2616e96f3e995a9f9514365)
举例如下:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_4.jpg?sign=1739582506-3zDLBQ6Sk9r9HXJhhLxIgpnacN3w6evW-0-7f374338a4e3eba9d11ff825fd67598c)
输出结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_5.jpg?sign=1739582506-jfhrtQAYshG4JvpnCx4cw5brEyv3Tl6h-0-ae8f49a1ed213404122459e4ac0ef196)
(2)for语句。for语句的格式为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_34_6.jpg?sign=1739582506-j1pa98qK3LAy2NoejHlckXOCHIjrNc2c-0-316bda3e6f75ca37366b464287589c0f)
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_1.jpg?sign=1739582506-SZBlzZvm6fKmOKNgpp9Uc6stwGrw0pOP-0-499cff43c6d08d95a2d9f367c8f36f95)
例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_2.jpg?sign=1739582506-GHWwJTcJMotwUkv400K3QontcVmBdEYy-0-e950f3f992357596608bc84d2cff0ba3)
输出结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_3.jpg?sign=1739582506-OHJuqexo87lnyDWOO9bGGnrRJRctEolk-0-4d5e71a03bb1dc906b3cc523422a8fed)
(3)while语句。while语句的格式为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_4.jpg?sign=1739582506-OqoLFbEKioZYwNAiZWaMDH5OhZ6Uoo2X-0-790e27d9c0e82c1c7b64d29f41abb628)
例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_5.jpg?sign=1739582506-wXqUcFt1q5lbolctE5QdicVma7cjeeTG-0-3bb53d8231cb1d92da400f77b098cbb6)
输出结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_6.jpg?sign=1739582506-dcUg9oZZ5JGmJZ5QQsdDkpl5s7JTrzDB-0-0c154be33aceff0c24f2f83e56d4697f)
(4)case语句。case语句的格式为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_35_7.jpg?sign=1739582506-hozwMSQUp1CNxf3E0g5zLebClx1goisg-0-0e939229521cbab9aef6a72745cb20e7)
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_36_1.jpg?sign=1739582506-IP5sKzGCFwoCq9ZH0ADJ0z1z8AsE8jnD-0-2cccce848b8d817ded167ebc0867f7d5)
例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_36_2.jpg?sign=1739582506-r3kw502WgfkgnPqDLTGLs6WAfu65TfEp-0-1506f24fbda8cedf384f9ec414a19c9a)
输入5,输出结果为:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_36_3.jpg?sign=1739582506-HpAg9kzL311MbsSKsR3T9oMq7zWMnq62-0-6c19b75f4d5b1f2e96508b6df712d58d)
2.1.5.5 Shell脚本的执行
运行Shell脚本的方法有两种:一种是在新进程中运行Shell脚本;另一种是在当前的进程中运行Shell脚本。
(1)在新进程中运行Shell脚本。
①将Shell脚本作为程序运行。Shell脚本也是一种解释执行的程序,可以在终端直接调用,如下所示:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_36_4.jpg?sign=1739582506-Y7UkU2DemZGgyYf07XWxR7Ry9H7OmwbP-0-be9e1e67beb8c3b0ab43b2ebb90a6e02)
在上述代码中,第2行中的“chmod+x”表示给test.sh增加执行权限;第3行用来执行当前目录下的test.sh。
②将Shell脚本作为参数传递给Bash解释器。将脚本文件的名字作为参数传递给Bash,例如:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_37_1.jpg?sign=1739582506-G8SCCBPPJGQD0lv3IDvnm9j2gIwQdQwu-0-eb8f5a58189c5f11f08077fae12d84a0)
通过这种方式运行脚本,不需要在脚本文件的第一行指定解释器信息。
③更加简洁的方法是运行bash命令。bash是一个外部命令,Shell会在“/bin”目录中找到对应的应用程序,即“/bin/bash”。修改如下:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_37_2.jpg?sign=1739582506-rZytCpnAzgFBSzcuTy4Ru1NgoMYot7Tm-0-74f84cda9cd0a8d3c01299e8c432302a)
(2)在当前进程中运行Shell脚本。需要用到source命令,source命令会读取脚本文件中的代码,并依次执行所有语句。source命令的用法如下:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_37_3.jpg?sign=1739582506-Yxd5L1Pb2M7x2fJHXHVzdcRZWH7bk7rJ-0-56b1f43444feea514c4a50228760e792)
例如,使用source命令运行test.sh,代码如下:
![](https://epubservercos.yuewen.com/05A69C/23020642901652606/epubprivate/OEBPS/Images/42374_37_4.jpg?sign=1739582506-UdADBivpD8JBBuKM9LA0e5EXpUYsjr0F-0-242dea79f8485f2516a41d60bb4dd857)