简介
概述:
- 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编程的基本概念
Shell脚本通过很多Linux命令通过Shell控制结构粘合形成的文本文件,一个Shell文件可以作为一个Linux以高效的方式执行命令,完成更复杂的管理控制功能,Shell脚本又叫Shell程序。
2.1.1 Shell脚本程序结构
- Shell可以包括脚本的句子Linux命令、赋值句、输入输出句和过程控制结构
- 举例
#!/bin/bash
list = `ls./temp` #赋值语句, ``表示输出是``内表达式值
for f in $list
do
mv ./temp/$f ./temp/$f.txt #变量前加$,表示引用该变量值
done
echo finished!
2.1.2 Shell脚本的创建和执行方法
- 创建shscri脚本
- 创建目录./temp以及目录中的一些文件
- 执行脚本,检查执行是否成功
- 给脚本增加可执行权限,然后执行
- 但是,执行任何虚假文件的权限都不够()
- shell脚本中不能随意添加空格,除了命令中的空格,命令中的空格只能控制一个,否则会报错
- 当./运行时总是提示: (bash: ./hello.sh: bin/bash: 坏的解释器: 没有文件或目录),但当使用时bash正确的操作,你需要检查你的脚本,把第一行改成 #!/bin/bash ,少写一个//
2.1.3 Shell变量和赋值表达式
Shell变量
- 可存储在变量中Shell脚本的其他命令使用程序中的一些命令产生的数据。。
- Shell变量的使用非常灵活,不需要事先定义变量,在赋值变量时会自动定义,Shell变量值的类型是字符串,任何字符串都可以赋值变量。
赋值表达式
- 可通过字符串常量,Shell变量引用、Linux命令直接输出拼接。
- 引用字符串常量和变量来区分,Shell要求用$来引用变量
- 若被引用的Shell字母、数字、下划线等字符应在变量名后用花括号{}包括变量名,否则bash变量名不能从正确的命名中提取。
- 为了区分赋值表达式Linux命令与字符串常量,Linux命令需要反引号``括起来
- 未经定义的Shell也可引用变量
示例
- 创建exvar.sh脚本
- 给脚本加执行权限,执行
2.1.4 Shell输入输出语句
- Shell用echo显示命令的表达式,包括变量值、字符串常量和命令输出
- 用read命令允许用户从键盘终端输入信息Shell变量。read命令格式:
read [-s] [-p prompt] variable1 variable2 …
- 上述语法表示用户输入多个字符串,依次存入Shell变量variable1、variable2……,使用bash当命令提取输入时,将空格作为字符串分隔符。
- -s:用户输入时无提示信息
- -p prompt:提示用户输入前显示提示串prompt
示例
- 创建io.sh脚本
- 执行脚本
2.1.5 终止脚本执行和终止
- 在Linux在系统中,任何命令和脚本执行后都有终止状态,即使命令不执行或不存在,也有终止状态
- 命令或脚本的终止状态码是介于0到255的整数。等于0表示执行成功,大于0表示执行失败。
(1)用户设置终止状态码
exit 状态码
(2)系统设置终止状态码
终止状态码 | 描述 |
0 | 命令执行成功 |
126 |
命令无法执行 |
127 | 没有找到命令 |
128 | 无效的终止参数 |
128+x | 使用Linux信号的致命错误 |
130 | 使用crtl+C终止进程 |
【Linux命令、脚本常见终止状态及描述】
Linux将进程(命令、脚本的执行)的终止状态保存在一个特殊的Shell变量?中,用命令:
查看终止状态
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语句格式
if condition
then
commands
fi
- 带else分支的if语句格式
if condition
then
commands
else
commands
fi
示例
- 创建condif1.sh
- 执行condif1.sh
- 创建condif2.sh
- 执行condif2.sh
- 创建condif3.sh
- 执行condif3.sh
- 修改文件让它走if分支
2.3.2 test命令
- test命令提供条件检测能力、如数值比较、文件属性检查、字符串比较等等。
- test命令算出的条件值为true,则test命令将其终止状态码置为0,if语句执行其then分支;若计算出的条件值为false,则test命令将其状态码置为非零,执行if的分支
- 命令格式:
- if then + 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 复合条件查询
if-then语句可以使用布尔逻辑来合并检查条件,可以使用两个布尔值
...[condition]&&[condition2]
...[condition]||[condition2]
示例:cmpand.sh
- 创建cmpand.sh
- 执行cmpand.sh
2.3.4 case语句
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*)default commands;;
esac
举例:condcase.sh
- 创建condcase.sh
- 执行condcase.sh
2.4 循环结构
2.4.1 for循环
for var in list
do
commands
done
do和done之间的命令序列是for循环体,这些命令可以用$var引用变量var的值,即当前迭代的列表项值。列表中指定值有几种不同的方法,如下:
(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循环结构
whlie test command
do
other commands
done
示例(loopwhile1.sh):
- 创建loopwhile1.sh
- 执行loopwhile1.sh
2.4.3 Util循环结构
until test commands
do
other commands
done
示例:(loopuntil.sh)
- 创建loopuntil.sh
- 执行loopuntil.sh
2.5 Linux全局变量和环境变量
2.5.1 Linux Shell层次结构
- 创建scope.sh
- 执行scope.sh
- 层次结构
2.5.2 Shell全局变量与局部变量
全局变量:所有Shell中可见
局部变量:仅在创建它的Shell中可见
- 创建scope2.sh
- 执行scope2.sh
2.5.3 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查看所有环境变量值
常用Linux环境变量
(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_name=(value1 …… valuen) #给整个数组赋初值,值之间用空格隔开
或
array_name[i]=value1 #给一个元素数组赋值,引用数组时必须用花括号括起数组元素名,格式为: ${array_name[index]}
示例:(array.sh)
- 创建array.sh
- 执行array.sh
2.6 Linux文件I/O、I/O重定向和管道
2.6.1 标准文件描述符
- Linux系统以文件处理功能见长,它把普通文件、I/O设备、网络连接都看成文件,从而便于将输入输出设备、网络通信连接统一看成文件I/O,简化I/O概念和I/O编程。
- Linux使用文件描述符(file descriptor)标识每个文件对象,文件描述符是一个非负整数,每个进程中多达1024个文件描述符(实际限额可用命令ulimit查看和设置)
- 前三个文件0 1 2用于特殊用途,分别表示标准输入、标准输出、标准错误输出
文件描述符 | 缩写 | 描述 |
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
3 | STDERR | 标准错误输出 |
2.6.2 I/O重定向
(1)输出重定向:
- >
- >> (追加)
(2)输入重定向:
- <
(3)标准错误输出重定向:
- 1>:正常输出被符号"1>"后的文件
- 2>:出错信息则被送到"2>"后的文件
2.6.3 管道
将一条命令的输出送往另一个命令(或脚本),这样可以给操作管道带来极大的方便。操作符号|,用管道连接命令的格式是:
command1 | command2
2.6.4 从文件获取输入
- 创建piperead.sh
- 执行脚本
2.7 命令行参数
向Shell脚本传递数据的另一种方式是使用命令行参数,可以在执行脚本时向命令行中添加数据。
示例:pospar1.sh
- 创建pospar1.sh
- 执行pospar1.sh
2.8 Shell函数
2.8.1 函数的基本用法
function关键字后面跟代码块
function name{ #name定义函数的唯一名称
commands
}
示例:fun1.sh
- 创建fun1.sh
- 执行fun1.sh
2.8.2 像函数传递参数
可以使用标准环境变量给函数传递参数。l例如,函数名在变量$0中定义,函数命令行的数目使用变量$1和$2等定义,专用变量$#可以用来确定传递给函数的参数数目。
示例:fun2.sh
- 创建fun2.sh:
- 执行fun2.sh: