《第7章Shell编程》由会员分享,可在线阅读,更多相关《第7章Shell编程(60页珍藏版)》请在金锄头文库上搜索。
1、Linux操作系统基础教程操作系统基础教程 人民邮电出版社人民邮电出版社安俊秀安俊秀安俊秀安俊秀 编著编著编著编著 成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/19目目 录录 CONTENTSCONTENTSp第第1 1章章 LinuxLinux概述概述p第第2 2章章 LinuxLinux的基本操作的基本操作p第第3 3章章 LinuxLinux文件系统与磁盘管理文件系统与磁盘管理p第第4 4章章 LinuxLinux用户及权限机制用户及权限机制p第第5 5章章 LinuxLinux文本处理文本处理p第第6 6章章 LinuxLinux多命令协作多命令协作p
2、第第7 7章章 ShellShell编程编程 p第第8 8章章 进程与设备管理进程与设备管理第7章Shell编程LinuxLinux操作系统基础教程操作系统基础教程 成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/19第第7 7章章 ShellShell编程编程pp7.17.1LinuxLinux编程基础编程基础7.1.17.1.1使用使用gccgcc编译C C程序程序7.1.27.1.2 使用使用makemake编译C C程序程序7.1.3 7.1.3 通通过编译源代源代码安装程序安装程序pp7.27.2ShellShell脚本脚本7.2.17.2.1什么是什么
3、是ShellShell脚本脚本7.2.27.2.2开始开始编写写ShellShell脚本脚本pp7 7.3.3变量及其使用方法变量及其使用方法7.3.17.3.1ShellShell变量和量和环境境变量量7.3.27.3.2变量的操作量的操作成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/19第第7 7章章 ShellShell编程编程pp7.47.4输入、输出和引用输入、输出和引用7.4.17.4.1输入与入与输出出7.4.27.4.2引用引用pp7.57.5分支控制语句分支控制语句7.5.17.5.1if if语句句7.5.27.5.2casecase语句句p
4、p7.67.6循环控制语句循环控制语句7.6.17.6.1whilewhile和和untiluntil循循环7.6.27.6.2forfor循循环7.6.3 7.6.3 跳出循跳出循环成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/19第第7 7章章 ShellShell编程编程pp7.77.7位置参数位置参数7.7.17.7.1获取位置参数取位置参数7.7.27.7.2位置参数使用案例位置参数使用案例pp7.87.8数组数组7.8.17.8.1为什么使用数什么使用数组7.8.27.8.2数数组的的创建、建、赋值和和删除除7.8.3 7.8.3 遍遍历访问数数组元
5、素元素成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/19第第7 7章章 ShellShell编程编程pp7.97.9函数函数7.9.17.9.1函数的定函数的定义与与调用用7.9.27.9.2在函数中使用位置参数在函数中使用位置参数7.9.3 7.9.3 使用函数返回使用函数返回值7.9.4 7.9.4 将函数保存到文件将函数保存到文件成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.1 7.1.1 使用使用gccgcc编译编译C C程序程序 我们使用的计算机在与低层硬件交互时使用一种称为机器语言的程序。机器语言是由一系列
6、二进制指令组成的,这些指令描述了一些非常基本的操作,如“指向内存中某个位置”“写入一字节”“删除一字节”等。如果程序员以这样的方式操作计算机将极其低效并难以理解,因此 Linux 提供了编译器将高级语言或汇编语言转化为机器语言。gcc 便是 Linux 环境中最常用的编译器。 gcc(GNU Compiler Collection)是 GNU 推出的多平台编译器,支持编译 C、 C+、 Java、 Objective C、 Fortran 等多种语言。 CentOS 默认已经安装了 gcc 编译器,读者也可以使用以下命令自行安装。 yum install gcc 下面以编译 C 程序为例,介绍
7、 gcc 的用法。在学习 C 语言时,我们都知道使用编译器编译 C 语言源代码经历了两个步骤:先将源代码编译成后缀名为.o 的目标文件,也就是机器语言;然后链接.o 文件,生成可执行文件。在 Linux 下使用 gcc 命令可以一次性完成这些工作。 gcc 的命令格式为: gcc options file 假设待编译的程序为当前目录下的 hello.c 文件,代码内容如下。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.1 7.1.1 使用使用gccgcc编译编译C C程序程序 #include main() printf(Hello World!n)
8、 使用 gcc 命令编译此文件: userlocalhost $ gcc -o hello hello.c userlocalhost $ ./hello Hello World! userlocalhost $ 可以发现 hello.c 已被编译成可执行文件,位置由-o 选项设置,如果未设置-o 选项,编译结果为当前目录下的 a.out 文件。 当程序依赖一个以上的文件时,可以先将每个文件编译成目标文件,再把所有目标文件链接成可执行文件。例如, hello.c 的 main 函数调用 greeting.c 中的 func 函数,代码如下。成都信息工程大学成都信息工程大学 并行计算实验室并行计
9、算实验室 2024/8/197.1.1 7.1.1 使用使用gccgcc编译编译C C程序程序 hello.c 文件内容: #include #includegreeting.h main() func(Tom); greeting.c 文件内容: void func(char *str) printf(Hello %s!n,str); greeting.h 头文件内容如下。 #ifndef _H_GREETING #define _H_GREETING void greeting(char *str); #endif成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8
10、/197.1.1 7.1.1 使用使用gccgcc编译编译C C程序程序 使用 gcc 命令的-c 选项,将.c 文件编译成.o 文件,然后将所有.o 文件链接成可执行文件。 userlocalhost $ gcc -c greeting.c userlocalhost $ gcc -c hello.c userlocalhost $ gcc -o hello hello.o greeting.o userlocalhost $ ./hello Hello Tom! userlocalhost $ 这样就完成了多文件依赖程序的编译。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室
11、 2024/8/197.1.2 7.1.2 使用使用makemake编译编译C C程序程序 make 可以获知所管理项目中源文件的修改情况,根据程序员设定的规则,自动编译被修改过的部分,而那些没有修改的部分将不会重新编译。这样既保证了程序的正确性,又大大提高了项目开发的效率。 那么 make 是如何知晓哪些文件被修改了?需要执行什么指令才能保证程序的正确?这涉及一个重要的文件makefile, make 通过 makefile 文件描述的内容自动维护编译工作。 makefile 文件需要程序员按照某种格式编写,并说明项目中各个源文件之间的依赖情况。在 Linux 系统中, makefile 文
12、件通常以 MakeFile 为文件名。为了说明 make 和 makefile 的工作原理,下面用一个简单的例子加以说明。 假设程序 prog 由 3 个源文件 file1.c、 file2.c 和 file3.c 编译生成,这 3 个源文件有各自的头文件 file1.h、file2.h 和 file3.h。通常情况下,编译器会生成 3 个目标文件 file1.o、file2.o 和 file3.o,然后用这 3 个目标文件链接成 prog 程序,其过程如下图所示。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.2 7.1.2 使用使用makemake
13、编译编译C C程序程序 要使用 make 对 prog 程序进行管理,则 makefile 文件应按如下内容编写。 prog:file1.o file2.o file3.o cc -o prog file1.o file2.o file3.o file1.o:file1.c file1.h cc -c file1.c file2.o:file2.c file2.h cc -c file2.c file3.o:file3.c file3.h cc -c file3.c 在该 makefile 文件中,第一行说明了程序 prog 由 3 个目标文件 file1.o、 file2.o 和 file3
14、.o 链接生成,第 3、第 5、第 7 行又说明了这三个目标文件依赖的 .c 文件及 .h文件。而第 2、第 4、第 6、第 8 行则是根据这些依赖关系,编译目标文件或可执行文件。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.2 7.1.2 使用使用makemake编译编译C C程序程序 make 的命令格式为: make flags macro definitions targets其中, flags 为标志位,常用的标志位选项如下表所示;macro definition 为宏命令,在这里指定的宏命令将覆盖 makefile 文件中的宏命令; ta
15、rgets 为要编译的文件,允许定义多个目标文件,按从左到右的顺序依次编译,如果此项缺省,则默认指向 makefile 文件中第一个目标文件。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.3 7.1.3 通过编译源代码安装程序通过编译源代码安装程序 许多发行商将自己开发的软件预编译成二进制库,用户下载解压后就能马上使用。尽管这样十分方便,但很多时候也需要通过编译源代码安装软件,这是由于: (1)软件开发商在更新版本时,会开发一些全新的功能,但为了程序的稳定性并不会将其加入当前的发现版本。因此想要获取最新的功能,必须通过编译源代码。 (2)有时候软件并
16、不能满足用户的全部需求,用户希望在程序中加入自定义的部分。这种情况也需要编译源代码。 在 Linux 系统中,许多程序都是直接提供源代码的,这样就可以利用 7.1.2 节介绍的 make 和 makefile 文件编译源代码并完成程序的安装。 pcre(Perl Compatible Regular Expressions)是一个 Perl 库,用于代替庞大的 Boost 来解决 C 语言中使用正则表达式的问题。 下面以安装 pcre 为例,介绍通过编译源代码安装程序的步骤。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.1.3 7.1.3 通过编译源代码
17、安装程序通过编译源代码安装程序 (1)登录 pcre 官方网站 http:/www.pcre.org/下载最新版本的 pcre 源代码,这里以 pcre2-10.23 为例。其中 wget 命令用来从指定的 URL 下载文件。 (2)解压 tar 文件。 (3)在目录中可以发现一个名为 configure 的脚本程序,它随着源代码一起发布。configure 脚本的作用是分析当前系统的环境,并且检查系统是否已经安装了必要的外部工具和组件,然后生成合适的 makefile 文件以便下一步编译。目前许多软件都是设计成可移植的,程序的源代码可以在各种 UNIX 系统上编译,在编译时,各系统之间会有细
18、微的不同,因此需要 configure 进行调整。另外, configure 还可以使用选项“-prefix” 指定程序的安装路径,默认路径为/usr/local。 (4)运行 configure。 (5)如果在检查过程中,发现了某些导致安装无法进行的问题,如缺少开发用的某些软件或开发库, configure 会以失败告终。若没有发现此类问题,则可以使用 make 命令编译程序。 (6)若编译顺利完成,则可以使用命令 make install 进行安装。该命令会在安装目录下生成可执行程序。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.2.1 7.2.1
19、什么是什么是ShellShell脚本脚本 到目前为止,我们都是以用户交互接口的方式使用 Shell 的,即人工通过输入设备在 CLI 命令行中输入命令,等待系统执行并将结果打印在屏幕上。设想一下,如果需要重复完成一个需要输入多条命令的任务,采用人工在命令行中一条一条输入的方法十分繁琐且容易出错,如果让 Shell 记住这些命令并自动完成输入将会大大提升效率(可以联想到上一节提到的 make)。因此将命令通过设计与组合后,记录到一个特定的文件中, Shell 就作为命令解析器执行文件中的一系列命令, 这里的文件就是 Shell 脚本。 简单来说, Shell 脚本是一个包含一系列命令的文件。 S
20、hell 读取这个文件,然后执行这些命令,就好像这些命令是直接输入命令行中一样。从这个角度看,作为用户交互接口的 Shell 和作为命令解析器的 Shell 所做的工作是完全一样的,大多数能在命令行中完成的工作都可以在 Shell 脚本中完成,反之亦然。而使用 Shell 脚本的原因除了刚才提到的效率问题外,还基于以下 3 点考虑。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.2.1 7.2.1 什么是什么是ShellShell脚本脚本 (1)简单性: Shell 是一个高级语言;通过它,可以简洁地表达复杂的操作。 (2)可移植性:使用 POSIX 定义
21、的功能,可以做到脚本无须修改就可在不同的系统上执行。 (3)开发容易:可以在短时间内完成一个功能强大又好用的脚本。 作为用户交互接口的 Shell 称为交互式 Shell,而作为命令解析器的 Shell 称为非交互式 Shell。因为它只需要通过 Shell 脚本就可以完成工作,不需要人为干预。需要特别注意的是,交互式 Shell 和非交互式 Shell 指的都是同一个 Shell。换句话说, Shell 既是交互式的又是非交互式的,这取决于用户如何使用它。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.2.2 7.2.2 开始编写开始编写ShellShe
22、ll脚本脚本 Shell 脚本本质上是 Linux 系统下的文本文件,通过第 5 章的学习我们已经掌握文本进行处理的方法。运用 vim 文本编辑器提供的“语法高亮”功能,可以很方便地编写 Shell 脚本。仍然以经典的 HelloWorld 程序为例,启动 vim 文本编辑器并输入以下内容。 #!/bin/bash #My first shell script. echo Hello World! 脚本第一行开头的“#!”是一个约定的标记,称为 shebang,用来告知操作系统需要用什么解析器来执行此脚本,这里表示使用 bash 来执行 Shell 脚本;第二行为注释,Shell 的注释以“#
23、”开头,与所有编程语言一样注释的内容不会执行,在命令行中也是如此。例如: userlocalhost $ echo Hello World! #This is a annotation Hello World!成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.2.2 7.2.2 开始编写开始编写ShellShell脚本脚本 编写完后将脚本保存为 HelloWorld.sh,这里的以 sh 为脚本扩展名并没有什么特殊含义,仅为了表明这是一个 Shell 脚本,达到见名知义的目的,类似于 python 脚本的.py 或 php 脚本的.php。 然后给文件增加可
24、执行权限,并运行。 userlocalhost $ chmod +x HelloWorld.sh userlocalhost $ ./HelloWorld.sh Hello World! userlocalhost $ 可以看到, Shell 脚本的执行结果和直接在命令行中输入命令的结果完全相同。在上面的例子中,使用三行内容的 Shell 脚本完成了命令行中一行命令的工作,这是为了向读者介绍编写 Shell 脚本最基本的方法,在本章后面的内容中将展示 Shell 编程强大的功能。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.1 Shell7.3.1
25、Shell变量和环境变量变量和环境变量 1Shell 变量 首先回顾一下在学习各种编程语言时对变量的定义。变量是一个用来存储数据的实体。每个变量都有一个变量名和一个值,其中变量名是引用变量的标识符,值是存储在变量中的数据。 与许多编程语言的变量一样, Shell 变量在命名时需要遵守一些规则:变量名必须由大写字母(AZ)、小写字母(az)、数字(09)或下画线(_)构成;变量名的第一个字符不能是数字。 对于变量的值 ,大多数编程语言都可以包含多种不同类型的数据,而 Shell 变量只有字符串一种类型,即无论给 Shell 变量赋予什么值,在存储时都会转换为字符串。Shell 变量只能在创建它的
26、 Shell 中使用,对于其他 Shell 是不可见的,并且 Shell 变量也不会从父进程传递给子进程,这一点与局部变量非常相似。因此在编写 Shell 程序过程中,当需要临时存储时,可以使用 Shell 变量。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.1 Shell7.3.1 Shell变量和环境变量变量和环境变量 2环境变量 在学习各种编程语言的变量时,往往会提及全局变量的概念。全局变量可以在程序的任何地方使用,通常设计成可供函数在任何时候进行获取和修改。在 Shell编程中,这一功能由环境变量实现。环境变量是一种特殊的变量类型,系统中的所
27、有进程都可以使用, 这与全局变量十分相似, 但环境变量并不完全等同于全局变量 ,因为子进程对环境变量的修改不会传递到父进程中,关于进程的内容将在第 8 章详细介绍。 环境变量的命名和值类型与 Shell 变量相同,但需要注意的是,在 bash 中,系统定义的环境变量全部使用大写字母命名,如 PATH。下表列出了 bash 中常用的环境变量以及它们的说明,其他类型的 Shell 环境变量的命名会有区别。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.1 Shell7.3.1 Shell变量和环境变量变量和环境变量 下面使用 PATH 介绍环境变量具有的全
28、局性, PATH 表示命令执行时系统的搜索路径,输出 PATH 的值如下。 userlocalhost $ echo $PATH /usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/user/.local/bin:/home/user/bin 命令执行时,Shell 会在以上目录中寻找命令。回顾上面的 HelloWorld.sh 脚本,在执行时是通过“./”的方式显式指定脚本的路径。而对于一些常用的脚本,通常会把它们放在 PATH 指定的目录里,运行时 Shell 自动
29、搜索,而不需要用户指定路径。因此将 HelloWorld.sh 脚本复制到 PATH 中的一个名为“/home/user/bin”的目录,这个目录是存放个人脚本的理想位置,然后再执行脚本。 userlocalhost $ cp HelloWorld.sh /home/user/bin/ userlocalhost $ HelloWorld.sh Hello World! userlocalhost $ 此时就不必显式指定脚本的路径了,这就是环境变量发挥的作用。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.2 7.3.2 变量的操作变量的操作 无论是
30、Shell 变量还是环境变量,对于它们的操作可以归纳为 4 种:创建变量、获取变量的值、修改变量的值和删除变量。 1创建变量 变量的创建十分简单,只需要指定变量名称和变量值,它们之间用等号(=)连接,等号两边不能有空格。创建变量的语法为: NAME=value 变量创建好后,可以使用$符号后面接变量名的方式获取变量的值。例如,定义一个名为 os 的变量,它的值为 CentOS,然后用 echo 命令输出变量的值。 userlocalhost $ os=CentOS userlocalhost $ echo $os CentOS 变量的值并不是必须的,如果变量在创建时没有赋值,则系统默认此变量的
31、值为null。另外,当使用$符号获取一个并没有被创建过的变量时,系统会自动创建变量,并为变量赋值为 null。例如,获取一个没有被创建的变量 os1。 userlocalhost $ echo $os1 userlocalhost $成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.2 7.3.2 变量的操作变量的操作 2获取变量的值 前面已经提到过,可以使用$符号获取变量的值。然而考虑一种情况,如果变量后面需要紧跟其他字符将怎么办呢?如需要将一个名为 file 的文件改名为 file1, 用户可以通过 mv 命令快速实现。而在实际编程当中,往往不会显式
32、地给出文件名,而是用变量的方式存储文件名,就目前学到的知识可以按下面的方式执行 mv 命令。 userlocalhost $ fname=file userlocalhost $ mv $fname $fname1 mv: missing destination file operand after file Try mv -help for more information. userlocalhost $ 在系统的错误提示中可以看到,在 file 后面缺少了参数。这是因为系统把fname1 当成了一个变量,因为此变量没有被创建,所以取值时为空值。为了区分变量名和变量名后面紧跟的字符,可以使
33、用花括号将变量名括起来。 userlocalhost $ mv $fname $fname1 userlocalhost $ 这样 Shell 就不会把 1 当成变量名的一部分了。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.2 7.3.2 变量的操作变量的操作 3变量的修改与删除 修改变量与创建变量使用相同的语法,如果变量已经存在,重复对它进行赋值就可以改变变量的值。例如,将 os 变量的值由 CentOS 改为 ubuntu。 userlocalhost $ os=CentOS userlocalhost $ os=ubuntu userloca
34、lhost $ echo $os ubuntu 环境变量的修改与 Shell 变量有所不同,因为子进程对环境变量的修改不会传递到父进程中。例如,在下面的例子中,编写脚本修改 PATH 环境变量,在当前 Shell 中执行此脚本,再查看当前 PATH 环境变量的情况。 编写脚本 test 如下。 PATH=PATH has been removed echo $PATH 运行脚本,并查看 PATH 环境变量。 userlocalhost $ ./test PATH has been removed成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.3.2 7.3
35、.2 变量的操作变量的操作 userlocalhost $ echo $PATH /usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/user/.l ocal/bin:/home/user/bin userlocalhost $ HelloWorld.sh Hello World! 对于 Shell 变量来说,通常不需要主动删除变量,因为 Shell 变量的生存周期只在当前 Shell。但是如果需要的话,可以使用 unset 命令。 unset 命令的格式为: unse
36、t NAME unset 命令同样可以删除环境变量。值得注意的是,用户可以通过 export 命令将 Shell 变量导出为环境变量,但没有办法将环境变量再恢复成 Shell 变量。换句话说,移除一个环境变量唯一的办法就是删除它。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.4.1 7.4.1 输入与输出输入与输出 1输出 在输出操作中使用得最多的是 echo 命令, echo 命令的功能是将字符串输出到屏幕。 echo 命令的格式为: echo -ne string 其中,string 表示要输出的字符串。选项 n 表示输出不换行,例如: userlo
37、calhost $ echo -n Hello;echo World! Hello World! 选项 e 表示处理特殊字符,例如,在下面的例子中,echo 命令识别并输出制表符“t”。 userlocalhost $ echo -e HellotWorld! Hello World! 除了 echo 外,还有一种功能更强大的输出命令printf。 Shell 中的 printf 命令与 C 语言中的 printf 函数非常相似,功能都是格式化输出数据。 printf 命令的格式为: printf format arguments.成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室
38、 2024/8/197.4.1 7.4.1 输入与输出输入与输出 其中, format 为输出的格式,arguments 为要输出的数据。使用 printf 输出时必须指定数据的格式,例如: userlocalhost $ printf %sn Hello World! Hello World! 其中格式部分用引号包围,单引号或双引号都可以。“%s”为格式符,表示输出的格式为字符串,类似的还有“%d”、“%c”、“%f”等,代表的格式与 C 语言中的相同。与 echo 命令不同的是, printf 不会自动换行,所以要达到换行的效果,就需要在格式最后加上换行符“n”。成都信息工程大学成都信息工
39、程大学 并行计算实验室并行计算实验室 2024/8/197.4.1 7.4.1 输入与输出输入与输出 2输入 有时候编写程序需要考虑到程序的交互性,更准确的话应该是程序与用户的互动能力。增加互动性最直接的办法就是从用户获取输入。在 Shell 中获取用户输入可以使用 read 命令。 read 命令的作用是从标注输入读取一行数据。 此命令可以用于读取键盘输入或应用重定向读取文件中的一行。 read 命令的格式为: read options variable 先通过一个简单的例子来感受一下 read 的用法。修改 HelloWorld.sh 脚本如下。 #!/bin/bash #My first
40、 shell script. echo Hello World! read os echo My Linux distribution is $os 然后运行脚本。 userlocalhost $ ./HelloWorld.sh Hello World!成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.4.1 7.4.1 输入与输出输入与输出 此时程序执行完 echo 的输出,等待 read 命令的输入。输入 CentOS 并按 Enter 键。 userlocalhost $ ./HelloWorld.sh Hello World! CentOS My L
41、inux distribution is CentOS read常用命令选项如表所示。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.4.2 7.4.2 引用引用 在 Linux 的日常使用中,需要输入各种命令。命令由字母、数字和一些其他字符组成,某些字符有其特殊的含义,如表示单条命令结束的分号“;”,重定向符,以及刚提到的变量取值符$等,我们将这些具有特殊含义的字符称为元字符。如果在输出时包含了元字符,但并不想使用它们的特殊功能该怎么办呢? 例如,想输出的内容是:“This pen is $1”,可能读者会按照下面的格式输入 userlocalhost
42、$ echo This pen is $1 This pen is 这并不是我们预期的输出,因为 Shell 使用了$的特殊功能,把 1 当成了变量。在这种情况中,我们可以采用转义字符“”加元字符的方式告诉 Shell 不使用特殊功能,并原样输出。 userlocalhost $ echo This pen is $1 This pen is $1 在上面的例子中,使用转义字符取消了元字符的特殊含义,这样的操作称为引用。理论上,转义字符可以满足所有需要引用的情况。但是如果需要引用的字符过多,插入转义字符时会降低命令的可读性。 userlocalhost $ echo I am using Li
43、nux(CentOS);My username is . I am using Linux(CentOS);My username is .成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.4.2 7.4.2 引用引用 这样使用多个转义字符,不仅麻烦而且命令不易阅读。为此 Linux 还提供了两种引用的方式:单引号引用和双引号引用。 以下是使用单引号的例子。 userlocalhost $ echo I am using Linux(CentOS);My username is . I am using Linux(CentOS);My username i
44、s . 单引号之间的所有内容都被引用了,这样做比使用转义字符高效许多。 3 种引用方式,读者可以根据实际需求选择使用任意一种或几种。 (1)转义字符:用于引用任意的单个字符。 (2)单引号引用:也称为强引用,用于引用包含的字符串。 (3)双引号引用:也称为弱引用,用于引用包含的字符串,但保留$、 和的特殊含义。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.1 if7.5.1 if语句语句 if 语句是最常见的分支语句,语法格式如下。 if expression; then command elif expression; then command e
45、lse command fi 通过命令行中的一个简单例子说明 if 语句的用法。 userlocalhost $ if true; then echo its true; else echo its false; fi its true userlocalhost $ if false; then echo its true; else echo its false; fi its false成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.1 if7.5.1 if语句语句 执行哪一个分支由 if 后的表达式结果决定。需要创建多分支时,可以使用 elif
46、 指定其余分支。 从 if 语句的结构可以看出,关键字 if、 else、 elif 等决定了语句的分支情况,而表达式决定了执行哪一条分支。表达式根据实际需求变化,在复杂的判断条件中,需要使用 test 命令或组合表达式的方式完成。 1test 命令 test 命令经常出现在 if 语句表达式的编写中,用于执行各种检查和比较。 test 命令的格式为: expression 先用一个例子说明 test 命令的使用方法。 if read -t 5 -p Enter the result of 4+4 in 5 seconds: result; then if $result -eq 8 ; th
47、en echo The result is correct! else echo The result is wrong! fi else echo -e nTime out! fi成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.1 if7.5.1 if语句语句 现在分析这个脚本。最外层的 if 语句后的表达式是一个 read 命令, -t 选项的存在使得 read 可以根据输入延迟返回不同的状态值,如果在 5 秒内输入,则返回 0 状态值,程序进入内层嵌套的 if 语句,否则进入外层 else 语句。在内层 if 语句中判断 result 变量的值,
48、方括号之间的内容为 test 命令,其中“-eq”是判断两个整数是否相等的表达式。整个 test 命令表示如果变量 result 的值等于 8,就返回 TRUE,否则返回 FALSE。通过 if 语句的分支控制,实现了程序判断对错和限制回答时间的功能。 bash 还提供了一个增强的 test 命令,命令格式如下。 expression 使用这种格式的 test 命令支持所有 test 命令表达式,并且增加了一个重要的功能支持正则表达式匹配。匹配符号为“=”,若“=”左边的字符串匹配了“=”右边的正则表达式,则返回 TRUE,反之返回 FALSE。 2组合表达式 有些时候分支的判定条件比较复杂,
49、 if 语句可以使用逻辑运算符将表达式组合起来,实现更复杂的计算。可用的逻辑运算符有 3 种,分别为逻辑与、逻辑或和逻辑非。这 3 种逻辑运算符的操作符与说明如下表所示。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.1 if7.5.1 if语句语句 下面是一个逻辑与的使用例子。这个脚本可用来检查一个数是否属于某个范围。 #!/bin/bash num=50 if $num -ge 40 & $num -le 60 ;then echo The number between 40 and 60. fi 在这个脚本中,检查变量 num 的值是否在 40
50、到 60 之间。 if 后的两个表达式被逻辑与运算符&分隔,判断顺序从左往右,只有前一个表达式为真时,才会判断下一个表达式,如果所有表达式为真,则返回 TRUE,否则返回 FALSE。 下面是一个逻辑或的使用例子。这个脚本可用来检查一个数是否在某个范围之外 #!/bin/bash num=20 if $num -lt 40 | $num -gt 60 ;then echo The number is outside 40 to 60. fi成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.1 if7.5.1 if语句语句 在这个脚本中,检查变量 num
51、的值是否在 40 到 60 之外。 if 后的两个表达式被逻辑或运算符|分隔,判断顺序仍然从左往右,但是只要一个表达式为真,就返回 TRUE,只有当表达式为假时,才会判断下一个表达式,如果所有表达式为假,则返回 FALSE。 逻辑非运算符!会对表达式的运算结果取反。如果表达式为 FALSE,则返回TRUE;反之,如果表达式为 TRUE,则返回 FALSE。因此为第一个例子中的表达式加上逻辑非运算符,将与第二个例子完全等价。 #!/bin/bash num=20 if !( $num -ge 40 & $num -le 60 );then echo The number is out of ra
52、nge! fi 需要注意的是,因为!运算符仅对后面的第一个表达式有效,所以需要将整个表达式用圆括号括起来。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.5.2 case7.5.2 case语句语句 在分支控制中, if 可以满足很多情况下的需求。但是当分支条件非常多时, if 语句也随之变长。 case 语句为多选择语句,可以用 case 语句匹配一个值与一个模式,如果匹配成功,则执行相匹配的命令。 case 语句格式如下。 case value in expression) command ; esac 符号 ) 前面的表达式称为待匹配的模式,取值将检
53、测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号*捕获该值。 另外 case 语句还支持多语句组合,使用 | 符号连接多个模式,可以达到在模式间“或”的功能。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.6.1 while7.6.1 while和和untiluntil循环循环 在编写一段需要重复运行的程序时,要明确哪些工作需要重复,什么时候结束。使用 while 命令或 until 命令可以达到这样的目的。 while 命令的语法格式如下。 while expression; do command
54、done until 命令的语法格式如下。 until expression; do command done 与 if 命令一样,while 和 until 会判断表达式的返回值,从而控制循环条件,这里的表达式也经常使用 test 命令。而 do 和 done 之间的为重复执行的命令。while 命令的表达式返回值为真时,循环一直进行,直到返回值为假。而 until 命令正好相反,当表达式返回为假时,循环一直进行,直到返回值为真。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.6.2 for7.6.2 for循环循环 Shell 中还提供了另一种循环结构
55、for 循环。在处理数值序列的循环时,for 循环比 while 循环和 until 循环有效。 for 循环使用 for 命令,其语法格式如下。 for ( expression1; expression2; expression3;);do command done for循环执行过程如下:先执行expression1,再判断expression2,若返回 TRUE,则进入循环执行command命令,完成每次循环后都需要执行 expression3。因此 for 循环等同于如下结构的 while 循环。 expression1 while expression2;do command ex
56、pression3 done for 循环还提供了另外一种命令格式,如下所示。 for variable in sequence; do command done成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.6.3 7.6.3 跳出循环跳出循环 在循环语句中,并不是只有循环条件能够控制循环。bash 还提供了两种在循环体内控制循环的命令: break 和 continue。其中 break 命令为跳出当前循环, continue 为开始下一次循环。下面的例子说明了这两个命令的用法。 编写脚本 bkANDctn.sh,在相同的循环中使用两种跳出命令。 #!
57、/bin/bash echo Example of break: for ( i=1; i6; i=i+1 );do if $i -eq 3 ;then break fi echo $i done echo Example of continue: for ( i=1; i6; i=i+1 );do if $i -eq 3 ;then continue fi echo $i done成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.6.3 7.6.3 跳出循环跳出循环 脚本 bkANDctn.sh 执行结果如下。 userlocalhost $ ./bkAN
58、Dctn.sh Example of break: 1 2 Example of continue: 1 2 4 5 通过这个例子可以理解两种跳出命令的区别。 在第一个循环中, 当变量 i 等于 3 时,执行 break 命令,然后程序就跳出了这个循环;而在下一个循环中,当变量 i 等于 3 时,跳过当前循环剩下的命令,继续下一次循环。 还需要注意的是,如果在嵌套的循环中使用跳出命令,只对 break 或 continue 所在的循环起作用,而不会影响外层循环。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.7.1 7.7.1 获取位置参数获取位置参数 大
59、部分 Linux 提供的命令都允许用户使用选项和参数来完成各种任务。例如,解压缩命令“tar -xzf xxx.tar”,其中“-xzf”和“xxx.tar”是以参数的形式传递给程序的。Shell 使用位置参数存储这些命令行中传入的内容,并可以使用$加上特殊的变量名获取位置参数。比如使用从 1 开始的整数依次存储每一个实参,如下面的例子所示。 编写脚本 parameter1.sh,输出 19 的位置参数。 #!/bin/bash echo $1 = $1 echo $2 = $2 echo $3 = $3 echo $4 = $4 echo $5 = $5 echo $6 = $6 echo
60、$7 = $7 echo $8 = $8 echo $9 = $9成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.7.1 7.7.1 获取位置参数获取位置参数 按下面的方式执行脚本 parameter1.sh。 userlocalhost $ ./parameter1.sh first second third fourth $1 = first $2 = second $3 = third $4 = fourth $5 = $6 = $7 = $8 = $9 = 通过这个简单的例子介绍了如何获取位置参数。如果实参大于 9 个,可以用大括号将大于一位数的变
61、量名括起来,如“10”。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.7.2 7.7.2 位置参数使用案例位置参数使用案例 1处理选项 在学习 while 循环时,介绍了一个显示系统信息的菜单脚本。在该脚本中,使用循环输入指令的方式与用户交互。然而在 Shell 中很少用这种方式,更多的是使用选项指定程序的运作。下面编写一个全新的脚本 show_info.sh,使用位置参数来代替菜单。 #!/bin/bash # check the argument number if $# -ne 1 ;then echo Invalid argument numbe
62、r, expected 1 received $# exit 1 fi case $1 in -n|-N) echo Your user name is $USER. ; -t|-T) echo -n Its ;date +%H:%M ; -d|-D) df -h ;成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.7.2 7.7.2 位置参数使用案例位置参数使用案例 -h|-H) echo Available option: echo -n or -N:Show user name. echo -t or -T:Show current time. ech
63、o -d or -D:Show disk info. echo -h or -H:Get help. ; *) echo -e Invalid option:$1nTry show_info.sh -h for help. ; esac 2处理字符串 上面的例子展示了使用位置参数接收用户选项的方法。然而在很多程序中,不仅需要选项,还需要用户提供一些参数以完成特定的工作。例如,前面已经说过的 tar xzf xxx.tar 命令便是提供了 xxx.tar 参数以供命令处理。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.8.1 7.8.1 为什么使用数组为什
64、么使用数组 目前我们使用的变量都是由变量名和变量值组成的,并且一个变量只能包含一个值,这种数据结构称为标量变量。如果在编程中需要使用多个数据,使用标量变量的方法将会产生多个变量,这样会影响计算机处理的效率,并且使用多个变量名也会给编程造成极大的麻烦。为了解决这些问题,在许多计算机语言中使用数组来存放数据类型相同的数据。在 Shell 中,因为没有数据类型的约束,数组的使用将更加灵活。 数组是可以在内存中连续存储多个元素的结构,也可以理解为是一次存放多个值的变量。数组由数组名、数组元素和元素下标组成,下图是一个数组在内存中的存储情况。 成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验
65、室 2024/8/197.8.2 7.8.2 数组的创建、赋值和删除数组的创建、赋值和删除 与 bash 中的其他变量一样,数组的创建和赋值可以同时进行,但是需要注明数组元素的下标。数组创建与赋值的命令格式如下。 arraysubscript=value 其中 array 为数组名,是数组的唯一标识;subscript 为从 0 开始的数组元素下标;value 为对应元素的值。下面是数组创建和赋值的例子。 userlocalhost $ array2=10 userlocalhost $ echo $array2 2 userlocalhost $ echo $array2 10 在这个例子中
66、,第一条命令将 10 赋值给数组 array 中下标为 2 的元素。在后面的两条命令中演示了访问数组元素的方法,在取数组元素的值时,需要用花括号指明数组元素的完整名称,以免 Shell 将元素名扩展成路径名。可以看出数组除需要注意元素下标外,使用方法和 Shell 变量非常相似。与其他编程语言不同的是,Shell 数组只会给赋值的元素分配内存,如这个例子中只为下标为 2 的元素分配了内存,而在其他编程语言中,下标为 0 和 1 的元素会被初始化为空值并占用内存。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.8.2 7.8.2 数组的创建、赋值和删除数组的
67、创建、赋值和删除 作为能够存储多个数值的数据结构,数组还支持一次赋值多个数据,命令格式如下。 array=(value1 value2) 其中 value1、 value2 等值依次赋予从下标为 0 开始的数组元素。例如: userlocalhost $ array=(one two three four) userlocalhost $ echo $array0 $array1 $array2 $array3 one two three four 对于数组的删除操作,可分为删除数组和删除数组中的指定元素。删除操作需要使用 unset 命令,删除数组的命令格式如下。 unset array 删
68、除数组中指定元素的命令格式如下。 unset arraysubscript成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.8.3 7.8.3 遍历访问数组元素遍历访问数组元素 在前面的例子中使用了下标的方式对数组元素进行创建和赋值等操作。 在处理多个值时,这么做显然没有发挥数组作用。特别是在一些数组长度不确定的情况下,就需要遍历访问数组中的每一个元素。循环是一种非常适合遍历数组的方法,如下面的例子使用循环对数组进行赋值和访问。 编写脚本 array1.sh,使用 for 循环对数组进行赋值,例如: #!/bin/bash array10=1 for ( i
69、=1; i10; i=i+1 );do array1$i=$array1$i-1*2 done 该脚本用一个等比数列的前 10 项为数组 array1 的前 10 个元素赋值。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.1 7.9.1 函数的定义与调用函数的定义与调用 函数可以看作是对特定代码的封装,用户定义函数后,可以在任何位置调用。 Shell 中函数的定义有以下两种格式。 function name command return 或者是: name() command return 这两种格式是等价的,其中 name 为函数名, return
70、 是可选项,表示函数的返回值。下面的脚本 func1.sh 演示了函数的调用方法。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.1 7.9.1 函数的定义与调用函数的定义与调用 #!/bin/bash myfunc() echo Calling the function! echo Before calling“ myfunc echo After calling“ 脚本 func1.sh 执行结果如下。 userlocalhost $ ./func1.sh Before calling Calling the function! After cal
71、ling 脚本执行时会跳过函数的定义部分,直接执行第一个 echo 命令,输出 Before calling。然后调用函数 myfunc,执行函数体中的命令,也就是第二个 echo 命令,输出“Callingthe function!”。函数执行完后,继续执行函数调用后的代码,即第三个 echo 命令,输出 After calling。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.2 7.9.2 在函数中使用位置参数在函数中使用位置参数 向函数传递参数与向脚本传递参数的情况非常相似, 使用的参数符号也与脚本中的位置参数相同。下面的例子演示了向函数传递
72、参数的情况。 脚本 func2.sh 中定义了函数 add,实现两个整数的加法运算,代码如下。 #!/bin/bash add() if $# -ne 2 ;then echo Invalid argument number,expected 2 received $# return fi echo $1+$2=$1+$2 add 2 2 脚本 func2.sh 执行结果如下。 userlocalhost $ ./func2.sh 2+2=4成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.2 7.9.2 在函数中使用位置参数在函数中使用位置参数 在这个
73、例子中,调用 add 函数时传递了两个参数,在 add 函数体中使用$1 和$2 接收了这两个参数,并且还使用 $# 判断参数数量的合法性。这些都与脚本的位置参数如出一辙,所以 Shell 函数可以被视为位于脚本中的迷你脚本。需要注意的是,函数体内部的 $1、 $#等符号代表传递给函数的相关参数,不能与脚本的位置参数相混淆。在本例中,add 函数的$1、 $2 和 $# 都为 2,而脚本位置参数 $1 和 $2 为空, $#为 0。成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.3 7.9.3 使用函数返回值使用函数返回值 函数中的关键字 return
74、 用于指定函数的返回值,返回值作为函数执行的结果返回给函数调用命令。前面提到过,Shell 函数是迷你的脚本,所以函数返回值类似于程序的退出状态,可以使用变量“$?”获取。例如,下面的例子在 add 函数中使用了返回值。 修改脚本 func2.sh 如下。 #!/bin/bash add() if $# -ne 2 ;then echo Invalid argument number,expected 2 received $# return fi return $1+$2 add 2 2 echo The result is $?成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室
75、 2024/8/197.9.3 7.9.3 使用函数返回值使用函数返回值 脚本 func2.sh 执行结果如下。 userlocalhost $ ./func2.sh The result is 4 在上面的例子中, add 函数返回了参数的运算结果,在函数调用完成后,使用变量 $? 接收到了返回值。尽管函数返回值与程序退出状态如此相似,但它们之间也存在区别。return 关键字只能用于函数中,表示将返回值提供给函数的调用命令; exit 关键字可以用于程序的任意位置,表示退出当前程序并将退出状态返回到父进程。因此,如果把脚本 func2.sh 返回运算结果的 return 改为 exit,就
76、只能在运行脚本的 Shell 中取得返回值。代码如下。 userlocalhost $ ./func2.sh userlocalhost $ echo $? 4成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.4 7.9.4 将函数保存到文件将函数保存到文件 利用函数可以将程序功能模块化,如前面将加法功能模块化到了 add 函数中。模块化最大的优势之一就是方便代码重用,现在只能在当前程序中使用 add 函数,如何让其他程序也使用 add 函数呢?可以将函数保存到文件中,程序在需要时可以读取文件中的函数,达到代码重用的目的。 读取文件可以使用 source
77、 命令, source 命令是 bash 的内部命令。功能是使 Shell 读入指定的 Shell 程序文件并依次执行文件中的所有语句。 source 命令格式如下: source filename 删除 func2.sh 中 add 函数以外的内容,并编写脚本 func3.sh 调用 func2.sh 中的 add函数,代码如下。 #!/bin/bash source ./func2.sh echo func3.sh calling add function add 14 17 echo The result is $?成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024
78、/8/197.9.4 7.9.4 将函数保存到文件将函数保存到文件 脚本 func3.sh 执行结果如下所示: userlocalhost $ ./func3.sh func3.sh calling add function The result is 31 脚本 func3.sh 使用 source 命令读取脚本 func2.sh,并调用其中的 add 函数。甚至可以将函数写入到 .bashrc 文件中,如下所示。这样函数在系统启动时将一直有效。 # .bashrc # Source global definitions if -f /etc/bashrc ; then . /etc/bas
79、hrc fi # Uncomment the following line if you dont like systemctls auto-paging feature: # export SYSTEMD_PAGER= # User specific aliases and functions成都信息工程大学成都信息工程大学 并行计算实验室并行计算实验室 2024/8/197.9.4 7.9.4 将函数保存到文件将函数保存到文件 add() if $# -ne 2 ;then echo Invalid argument number,expected 2 received $# return fi return $1+$2 从以上例子可以看出,将函数保存到文件中,可以使其他程序重用一些常用代码,这在大型项目中是非常常见的。