简介
概述:
- Linux中的Shell作为用户与操作系统的接口,是用户使用操作系统的接口。Shell既是命令解释器,又是一种编程语言。
- 作为命令解释器,Shell是一个终端窗口,接受用户输入的命令,识别、解释、执行该命令,并向用户返回结果,功能类似Windows系统中的cmd.exe程序。
- 作为编程语言,Shell提供了变量、流程控制结构、引用、函数、数组等功能,可将公共程序、系统工具、用户程序“粘合”在一起,创建Shell脚本,实现更复杂的功能。
- Linux的很多管理任务是通过Shell脚本实现的,如Linux启动过程中通过运行/etc/rc.d目录下的脚本来执行系统配置和建立服务的。Shell还可用于用户工作环境的定制。
- 每个Linux系统发行版本中都包含多种Shell,一般有Bash,Bourne,TC Shell,C Shell和Korn Shell等等。其中Bash吸收和继承了其他Shell的优点,成为当前应用最广泛的Shell,是Linux Shell的事实标准。
学习目标:
- 掌握Shell脚本、变量、表达式、数学运算、字符串处理、输入输出的语法结构
- 掌握使用Shell条件和条件、选择、循环三大控制结构的基本编程方法
- 理解全局变量、局部变量、命令行参数的基本概念与用途
- 掌握文件I/O和I/O重定向的基本编程方法
- 理解Shell函数
2.1 Shell编程基本概念
2.1.1 Shell脚本程序结构
- Shell脚本的语句可以包括Linux命令、赋值语句、输入输出语句和流程控制结构
- 举例
2.1.2 Shell脚本的创建与执行方法
- 创建shscri脚本
- 创建目录./temp及目录下的一些文件
- 执行脚本并查看是否执行成功
- 给脚本加可执行权限然后执行
- 但对任意为假权文件执行会显示权限不够(我这里脚本执行了两次,所以有两个.txt)
注意:
- shell脚本中不能随便加空格,除了命令中的空格,且命令中的空格只能控一个,否则会报错
- 当./运行时总是提示: (bash: ./hello.sh: bin/bash: 坏的解释器: 没有那个文件或目录),但是当用bash运行时正确,你需要查看一下你的脚本,应该把第一行改成 #!/bin/bash ,少写了一个/
2.1.3 Shell变量与赋值表达式
Shell变量
- 可以用变量存储Shell程序中一些命令产生的数据,供脚本的其他命令使用。用户变量可以是任何不超过20个字母、数字或下划线的文本字符串,用户变量区分大小写。
- Shell变量的使用非常灵活,不必事先定义变量,在给变量赋值时会自动获得定义,Shell变量值的类型都是字符串,可以将任何字符串赋值给变量。
赋值表达式
- 可以由字符串常量、Shell变量引用、Linux命令直接输出拼接而成。
- 为区分字符串常量与变量引用,Shell要求用$来引用变量
- 若被引用的Shell变量名后紧接着字母、数字、下划线等字符,则应将变量名用花括号{}括起来,否则bash无法从正确的命名中提取变量名。
- 为区分赋值表达式中的Linux命令与字符串常量,Linux命令需要用反引号``括起来
- 未经定义的Shell变量也可引用
示例
- 创建exvar.sh脚本
- 给脚本加执行权限并执行
2.1.4 Shell输入输出语句
示例
- 创建io.sh脚本
- 执行脚本
2.1.5 终止脚本执行和终止状态
(1)用户设置终止状态码
(2)系统设置终止状态码
终止状态码 | 描述 |
0 | 命令执行成功 |
126 | 命令无法执行 |
127 | 没有找到命令 |
128 | 无效的终止参数 |
128+x | 使用Linux信号的致命错误 |
130 | 使用crtl+C终止进程 |
【Linux命令、脚本常见终止状态及描述】
2.2 Shell数学运算与字符串处理
2.2.1 Shell数学运算
两种数学运算机制
- 一种是使用expr命令,格式为expr expression
- 另一种是利用美元符号和方括号把数学表达式括起来,格式为$[expression],第二种用的比较多
示例
- 创建arith.sh
- 执行脚本
2.2.2 Shell字符串处理
功能 | 编程方法 |
截取字符串 | ${str:pos} ${str:pos:len} 功能:在字符串str中,抽取从位置pos开始,长度为len的字串。注意,下表从1开始 |
计算字符串长度 | ${string} expr length $string 功能:计算字符串string长度 |
计算字串的出现位置 | expr index $string substring 功能:在字符串string中找字串substring第一次出现的位置,若找不到返回0或1 |
返回匹配到的字串的长度 | expr index $string substring 功能:返回string从头开始匹配substring的字串的长度,若找不到,返回0 |
删除字符串 | ${string#substring} 功能:删除string开头处与substring匹配的最短字串 ${string##substring} 功能:删除string开头处与substring匹配的最长字符串 |
2.3 Shell条件与if控制结构
2.3.1 if语句
if语句
- 不带else分支的if语句格式
- 带else分支的if语句格式
示例
示例2-1:condif1.sh
- 创建condif1.sh
- 执行condif1.sh
示例2-2:condif2.sh
- 创建condif2.sh
- 执行condif2.sh
示例2-3:condif3.sh
- 创建condif3.sh
- 执行condif3.sh
- 修改文件让它走if分支
2.3.2 test命令
(1)数值比较
比较 | 描述 |
n1 -eq n2 | 检查n1是否等于n2 |
n1 -ge n2 | 检查n1是否大于等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于等于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
举例:cmpnum.sh
- 创建cupnum.sh
- 执行cupnum.sh
(2) 字符串比较
比较 | 描述 |
str1=str2 | 检查str1与str2是否相等 |
str1!=str2 | 检查str1与str2是否不同 |
str1<str2 | 检查str1是否小于str2 |
str1>str2 | 检查str1是否大于str2 |
-n str1 | 检查str1的长度是否大于0 |
-z str1 | 检查str1的长度是否为0 |
示例:cmpstr.h
- 创建cmpstr.h
- 执行cmpstr.h
(3)文件比较
比较 | 描述 |
-d file | 检查file是否存在并且是一个目录 |
-e file | 检查file是否存在 |
-f file | 检查file是否是一个文件 |
-r file | 检查file是否存在并且可读 |
-s flie | 检查file是否存在并且不为空 |
-w file | 检查flie是否存在并且可写 |
-x file | 检查file是否存在并且可执行 |
-O file | 检查file是否存在并且被当前用户拥有 |
-G file | 检查file是否存在并且默认值为当前用户组 |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -oz file2 | 检查file1是否比file2旧 |
示例1:cmpfile1.sh
- 创建cmpfile1.sh
- 执行cmpfile1.sh
示例2:cmpfile2.sh
- 创建cmpfile2.sh
- 执行cmpfile2.sh
2.3.3 复合条件查询
示例:cmpand.sh
- 创建cmpand.sh
- 执行cmpand.sh
2.3.4 case语句
举例:condcase.sh
- 创建condcase.sh
- 执行condcase.sh
2.4 循环结构
2.4.1 for循环
(1)读取列表或变量中的值(loopfor1.sh)
- 创建loopfor1.sh
- 执行loopfor1.sh
(2)读取命令结果中的值(loopfor2.sh)
- 创建loopfor2.sh
- 执行loopfor2.sh
(3)使用通配符(loopfor3.sh)
- 创建loopfor3.sh
- 执行loopfor3.sh
2.4.2 while循环结构
示例(loopwhile1.sh):
- 创建loopwhile1.sh
- 执行loopwhile1.sh
2.4.3 Util循环结构
示例:(loopuntil.sh)
- 创建loopuntil.sh
- 执行loopuntil.sh
2.5 Linux全局变量和环境变量
2.5.1 Linux Shell层次结构
- 创建scope.sh
- 执行scope.sh
- 层次结构
2.5.2 Shell全局变量与局部变量
- 创建scope2.sh
- 执行scope2.sh
2.5.3 Linux环境变量
Linux常用环境变量的名称和描述
变量 | 描述 |
PATH | 冒号隔开的目录列表,Shell将在这些目录中查找命令 |
LD_LIBRARY_PATH | 程序运行过程中查找第三方库的目录路径,以冒号隔开多个目录 |
C_INCLUED_PATH | C编译过程中查找第三方头文件路径,以冒号隔开多个目录 |
CPLUS_INCLUDE_PATH | C++编译过程中查找第三方头文件路径,以冒号隔开多个目录 |
JAVA_HOME | java开发环境所在目录 |
UID | 当前用户ID |
HOME | 当前用户的主目录 |
USER | 当前用户名 |
SHELL | 当前Shell类型 |
PWD | 当前工作目录 |
- 用echo命令或赋值语句读取变量值
- 可用env查看所有环境变量值
(1)命令搜索路径环境变量PATH
- 我们发现,如果命令串只给文件名会出错
- 为了探究原因,我们先查看环境变量PATH保存的命令搜索目录列表是什么:
发现里面没有home/shiyanlou:(即scope.sh所在目录)
- 将文件路径"."添加到PATH路径中
- 再直接输文件名就能执行该命令了
(2)开发工具安装位置环境变量
安装完开发工具后,安装程序会为它们创建一个环境变量,保存到它们的安装位置,一般取名为“大写的工具名称_HOME”。这些软件本身会携带一系列操作命令,一般放到其子目录bin中。因此为了方便运行这些命令,应该手动或自动将相应的bin命令添加到环境变量PATH的目录中。如安装Hadoop后,将$HADOOP_HOME/bin添加到PATH中。
但这样的话,只有在该窗口才能用。为了每次开机后都能使,需要把设置PATH的命令放在初始化脚本文件中。
系统初始化脚本有多个,Ubuntu中,/etc/profile是系统化脚本,对所有用户生效。$HOME/.profile是用户登录初始化脚本,放在该文件中的设置对所有终端窗口生效。$HOME/.bash_rc是终端窗口初始化脚本,仅对当前窗口初始化有效。
(3)C/C++应用开发与运行相关环境变量(3个)
- LD_LIBRARY_PATH:保存应用程序运行时搜索到的自定义或第三方共享库(动态库)路径列表
- C_INCLUDE_PATH:保存第三方C语言库函数API的头文件目录列表,作为gcc默认查找的头文件目录;
- CPP_INCUDE_PATH:保存第三方C语言库函数API的头文件目录列表,作为g++默认查找的头文件目录;
2.5.4 Shell变量的删除和只读设置方法
- 变量都是占用内存的,不用可以删除:unset
- 变量一般可读写,但readonly或declare -r可设置为只读。定义为只读后,变量不能再被赋值。
2.5.5 Shell数组的定义和使用方法
示例:(array.sh)
- 创建array.sh
- 执行array.sh
2.6 Linux文件I/O、I/O重定向和管道
2.6.1 标准文件描述符
文件描述符 | 缩写 | 描述 |
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
3 | STDERR | 标准错误输出 |
2.6.2 I/O重定向
(1)输出重定向:
- >
- >> (追加)
(2)输入重定向:
- <
(3)标准错误输出重定向:
- 1>:正常输出被符号"1>"后的文件
- 2>:出错信息则被送到"2>"后的文件
2.6.3 管道
将一条命令的输出送往另一个命令(或脚本),这样可以给操作管道带来极大的方便。操作符号|,用管道连接命令的格式是:
2.6.4 从文件获取输入
- 创建piperead.sh
- 执行脚本
2.7 命令行参数
示例:pospar1.sh
- 创建pospar1.sh
- 执行pospar1.sh
2.8 Shell函数
2.8.1 函数的基本用法
示例:fun1.sh
- 创建fun1.sh
- 执行fun1.sh
2.8.2 像函数传递参数
示例:fun2.sh
- 创建fun2.sh:
- 执行fun2.sh: