shell脚本和编程 | 青训营笔记

71 阅读5分钟

💡Shell是一种命令行界面,也是一种编程语言, 熟练掌握 Shell 能够大大提升 Unix/Linux环境下的工作效率。本课程将从其发展历史、基础语法开始,通过示例逐步深入, 学习使用 Shell ,也在一定程度上去理解 Shell 的执行原理和语法设计

主要内容

1.Shell基本概念

shell是一种命令解释器,处于用户与内核之间,提供用户与内核进行交互的接口。Shell负责接收用户输入的命令,将命令送入内核中执行。而计算机内核接收到用户的命令后调度相应的硬件资源完成操作,再将结果返回给用户。bash和cmd都是shell的一种具体形式。Shell与内核及用户间的关系如图所示

同时Shell也是一种脚本语言。作为命令语言,Shell交互式解释和执行用户输入的命令或执行预先设定好的一串命令;作为程序设计语言,Shell也定义了各种变量和参数,也有循环、分支等语言结构。在 Shell 中输入的命令,有一部分是 Shell 本身自带的,这叫做内置命令;有一部分是其它的应用程序(一个程序就是一个命令),这叫做外部命令。Shell 本身支持的命令并不多,功能也有限,但是 Shell 可以调用其他的程序,每个程序就是一个命令,这使得 Shell 命令的数量可以无限扩展,其结果就是 Shell 的功能非常强大,完全能够胜任 Linux 的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。

总的来说,Shell是命令解释器,也还是一门编程语言,因此它具有两者的综合的功能,具体如下图所示:

2.命令和语法

2.1 变量

作为一门编程语言,其最基本的就是变量。Shell中的变量可以分成三大类,即自定义变量、环境变量、系统环境变量。这三种变量的作用域、声明方式各有不同,具体如下图所示。

每个shell进程有一个自己的运行环境,不同的Shell进程有不同的Shell环境。Shell解析命令行、调用命令行的过程都在这个环境中完成。

环境变量

在环境变量中存在着当前Shell(父Shell)及其子Shell。所谓子shell,即从当前shell环境中新开了一个shell环境,这个新开的shell环境就是子shell,而开启子shell的环境称为该子shell的父shell。子Shell的本质可以理解为Shell的子进程,子进程的概念是由父进程的概念引申而来的,在Linux系统中,系统运行的应用程序几乎都是从init(pid为1的进程)进程派生而来的,所有这些应用程序都可以视为init进程的子进程,而init则为它们的父进程。

父子Shell是如何执行的呢?Shell脚本是从上至下、从左至右依次执行每一行的命令及语句的,即执行完一个命令之后再执行下一个。如果在Shell脚本中遇到子脚本(即脚本嵌套),这个子Shell也会从父Shell中继承很多环境,会先执行子脚本的内容,完成后再返回父脚本继续执行父脚本内后续的命令及语句。如下图所示:

自定义变量

自定义变量的变量名是由任何字母、数字和下划线组成的字符串,且不能以数字开头。并且对大小写敏感,区分字母大小写,例如:Var1和var1是不同的。另外,变量、等号、值中间不可以出现空格。Shell是弱类型语言,声明的每个变量都默认是字符串类型。

基本语法:变量名=变量值 例如 page_size = 10

查询变量语法:使用变量名查询 pagesize或者使用花括号page_size 或者使用花括号 {page_size}

删除变量:unset 变量名 unset page_size

导出环境变量:export 变量名

对于Shell如何声明非字符串的变量呢?可以通过declare来声明 例如声明变量为整型 declare -i total = page_size*page_num。declare声明变量的具体规则如下:

系统环境变量

一些常见的系统环境变量其含义如下表所示:

2.2 运算符和引用

Shell中一些常见的操作运算符如下表所示:

Shell和其他语言一样有算术运算符、逻辑运算符、比较运算符,其作用也一致。值得注意的是,Shell中的单引号、双引号、反引号有着很大的区别。单引号内的内容将原样输出;双引号的作用也是将引号里面的内容输出,但是,如果引号内有命令、变量等,会先对命令进行执行并得到结果、变量解析并得到结果,然后把结果输出。反引号与$()作用大致相同,都是用于命令替换,即对引用的命令进行执行。

2.3 管道

Shell管道操作符是 | ,语法:cmd1 | cmd2

要求:管道右侧的命令必须能接受标准输入才行,比如grep命令,ls、mv等不能直接使用,可以使用xargs预处理

注意:管道命令仅仅处理stdout,对于stderr会忽略,可以使用set -o pipifail设置shell遇到管道错误退出。

使用示例如下:

(grep功能:分析一行信息,若当中有感兴趣的信息,就将该行拿出来,可以用于正则表达式)

2.4 重定向

文件描述符:

0: 标准输入流(stdin)

1: 标准输出流(stdout)

2: 错误输出流(stderr)

重定向管道:

> 覆盖的方式写入

>> 追加的方式写入

< 输入流重定向

特殊符号:

&: 重定向时, 用于标记现有的流. 为了区分文件名和文件描述符.

如: 2>&1, 意思是将错误输出流重定向到标准输出流的文件中

&-: 特殊标识, 将标识符关闭. 1>&-

使用方式:

[n]>a.log: 重定向到文件

[n]>&[m]: 将描述符n重定向到描述符m

<a.log: 从文件中读取输入

具体使用实例如下:

# 将命令的输出重定向到文件
command 1>a.log
# 重定向输出时, 若不写描述符, 默认为标准输出流
command >a.log
# 重定向的位置不重要
>a.log command
# 重定向输入流
0<1.txt cat
# 重定向输入时, 默认为标准输入流
<1.txt cat
# 标准输入关掉
exec 0<&-
# 将一段字符串作为输入
cat <<TAG
内容
TAG
# 将标准输出关闭, 效果与 1>/dev/null 相同
command 1>&-
# 丢弃标准输出和错误输出
command >/dev/null 2>&1

2.5 判断命令

命令

  1. test 语法:test condition
  2. [] 语法:[condition]
  3. [[]] 语法:[[condition]]

整数测试

用来测试表达式是否成立,若成立返回0,否则返回其他数值。它只能用来判断是否成立,无法判断是否正确。例如:

常用的测试操作符

操作符含义
-eq等于(Equal)
-ne不等于(Not Equal)
-gt大于(Greater Than)
-lt小于(Lesser Than)
-le小于或等于(Lesser or Equal)
-ge大于或等于(Greater or Equal)

字符串测试

主要测试字符串是否存在或对两个字符串进行比较。搭配使用的常见测试操作符及其含义如下表所示:

常用的测试操作符含义
=第一个字符串与第二个字符串内容相同
!=第一个字符串与第二个字符串内容不同,!号表示相反的意思
-z检查字符串内容是否为空,对于未定义或赋予空值的变量将视为空串

字符测试用例如下所示:

文件测试

主要测试文件的类型和权限。搭配使用的常见测试操作符及其含义如下表所示:

常见的测试操作符含义
-d测试是否为目录(directory)
-e测试目录或文件是否存在(Exist)
-f测试是否为文件(File)
-r测试当前用户是否有权限读取(Read)
-w测试当前用户是否有权限写入(Write)
-x测试当前用户是否有权限执行(eXcute

文件测试test用例如下:

2.6 分支语句

对于分支语句,if语句和case语句,shell的写法如下:

if条件语句

if condition ; then

程序段

elif condition ; then

程序段

esle

程序段

fi

其使用举例如下:

Case语句

case $变量 in:

”第一个变量内容“)

程序段

;;

”第二个变量内容“)

程序段

;;

*)

程序段

;;

esac

其使用举例如下:

2.7 循环

shell中的循环语句有三种,while循环、until循环、for循环。

其应用举例如下:

3.执行过程和原理

3.1执行

  1. shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器执行。例如使用bash执行:

  1. 启动方式 启动方式可以是直接文件名运行也可以是解释器执行,或者source运行

3.2 执行过程

  1. 字符解析
  2. shell展开,例如{1..3}解析为1 2 3
  3. 重定向,将stdin、stdout、stderr的文件描述符进行指向变更
  4. 执行命令 builtin 直接执行 非builtin使用$PATH查找,然后启动子进程
  5. 收集状态并返回

3.3 shell展开

  1. 大括号展开 {...}
  2. 波浪号展开 ~
  3. 参数展开 ${}
  4. 命令替换
  5. 数字计算 $((...))
  6. 文件名展开 *?[..]外壳文件名模式匹配

课程总结

参考链接

重定向

条件语句、文件测试

条件语句 测试命令

管道

自定义变量及赋值