Shell编程

ppgo8 于 2023-02-03 发布

Shell编程

Shell基础

​ 大多数Linux发行版不安装桌面环境,需要使用Shell管理操作系统。

​ Shell是一个命令解释器,一次命令交互的过程为:Shell将用户输入的命令解释称Linux内核能够识别的命令,传递给内核执行,内核返回执行结果给Shell,Shell显示输出结果。

​ Shell分类:

​ Shell命令的各种组合形成了Shell脚本(Shell Scipt)。Shell脚本的主要内容就是各种命令,每个命令可以单独执行,经过一系列操作符的连接、判断、循环形成了新的编程语言。

Shell脚本中的‘’hello world‘’

image-20230203160825379

image-20230203160719652

image-20230203160811078

创建并执行Shell脚本的基本流程:

  1. 文本编译器创建 .sh文件
  2. 写入代码
  3. 添加执行权限
  4. 执行

变量

​ Shell不严格区分变量类型,变量类型取决于内存中存储的内容。在第一次给变量赋值时决定变量类型。同时,未声明类型的变量,在赋值时会自动进行转换。

变量声明

变量赋值

变量引用

语法

$变量名      # 最简便 
${变量名}    # 适用在变量名之后还有其他字符在
"$变量名"    # 避免变量值中空格的干扰
"${变量名}"  # 避免变量值中空格的干扰

变量分类

Shell中的引号

​ 在Shell中,对字符串并没有严格的引号要求。如果字符串中包含有空格,那么就需要经字符串包含到引号中去。因为空格后的字符可能被当做命令的选项或参数,可能会出错。

注意双引号之中对变量的引用能够正常的输出变量值;单引号之中对变量的引用不能正常的输出变量值。

所以有时不想引用变量值可以使用单引号。

变量的间接引用

间接引用,是指某个变量的值是另外一个变量的变量名的情况。Shell使用!操作符实现间接引用。

命令别名

​ 在Shell的使用过程中,很多时候会遇到很长的命令。可以起别名进行替换。

语法

alias newname=command

运算符

算术运算符

​ Shell中常用的算术运算符

++、-- 
+、-
*
/
%

位运算符

Shell中常见的位运算符

~     # 按位取反 
<<、>> # 左移、右移
&  # 按位与
^  # 按位异或
|  # 按位或

逻辑运算符

​ 使用逻辑运算符可以实现多个条件的测试。

-a # 逻辑与 
-o # 逻辑或

!  # 逻辑非
&& # 逻辑与
|| # 逻辑或

三元运算符

三元运算符?,语法

表达式1 ? 表达式2 : 表达式3
# 表达式1 条件判断
# 如果未真 输出表达式2
# 如果为假 输出表达式3

​ 三元运算符需要三个表达式。

image-20230204133035215

赋值运算符

​ 注意赋值运算符左右两侧不可以有空格

运算符优先级

let命令

let是Shell中的内部命令,功能是计算一个算术表达式。

语法

let 表达式

其他常见表达式

除了let命令外,还有由符号组成的表达式运算操作,这些语法更常用更方便

语法

$((表达式))
$[表达式]

条件测试

​ 在Shell中通过成条件判断为条件测试。

条件测试语法

​ Shell支持三种条件测试语法

test conditicon   # test内部命令,检测表达式是否为真,返回TRUE or False
[ condition ]     # 常用,注意条件左右距离 [] 有一个空格
[[ condition ]]   # 比第二种更严谨,第二种有时候会出错 

文件测试

​ 文件测试主要是判断

​ 常用操作如下:

-d file  # 检测是否是目录,如果是。返回true
-f file  # 检测是否是文件,如果是。返回true
-r file  # 检测文件是否可读,如果是,返回true
-w file  # 检测文件是否可写,如果是,返回true
-x file  # 检测文件是否可执行,如果是,返回true
-s file  # 检测文件是否为空,不为空返回true
-e file  # 检测文件(包括目录)是否存在,如果存在返回true

注意】在条件测试时,0为真、1为假,与大多数编程语言相反。

image-20230203163954016

​ [-e pp]命令的返回结果 自动复制给?操作符,(?操作符是一个特殊变量,作用是保存上一次命令执行的返回值)

,适用$操作符引用并输出结果。

​ 此时的输出结果为0,也就是真值,pp文件时一个目录。

字符串测试

​ 常用的字符串操作符如下

<   # ASCII顺序,前面的字符串小于后面的字符串为真
>   # 大于
==  # 字符串完全相同为真 
=   # 字符串相等为真
=~  # 前面的字符串包含后面的字符串为真
!=  # 字符串不相等为真
-z  # 字符串为空则为真
-m  # 字符串非空为真

【注意】以上所有操作符在使用时,必须两侧都有空格才可以。在赋值时,两侧都不可以有空格。

image-20230203170710388

整数值的测试

​ Shell对整数值的测试是使用字符操作符,而不是常用的算术运算符。

​ 常用的操作符如下:

-eq # 两个数相等为真
-ge # 前者大于等于后者为真
-gt # 前者大于后者为真
-le # 前者小于等于后者为真
-lt # 前者小于后者为真
-ne # 两个数不相等为真

分支语句

if语句

if语法

if [条件测试];then +
	条件测试为真时执行语句
elif [条件测试];then 
	条件测试为真时执行语句
else 上述测试都为假时执行该语句
fi 

​ 同上,shell脚本中每一行一条语句即可执行。如果想将多条语句写在同一行,需要使用;分割。

case语句

​ if结构中,如果条件测试多于一个,可以用elif进行判断,但是当条件测试太多了,结构会太复杂。可以使用case结构处理多分支的情况。

​ case语法

case "变量值" in
	"var1")
		语句
		;;
	"var2")
		语句
		;;
	"var3")
		语句
		;;
		*)
		语句
		;;
esac 

​ 变量值为需要判断的值,var1-var3为匹配条件,case结构在执行时,Shell会一次将变量值与后续的匹配条件进行匹配。如果有匹配,则执行匹配后的语句,如果全部不匹配,则执行*代表的分支,如果没有*分支,则直接退出执行。

​ case结构中,行尾必须是in关键词,每个匹配条件后必须有一个),每个条件分支都有两个连续的;,表示分支结束。

image-20230203180414681

image-20230203180501611

​ case匹配中,可以使用正则表达式。

循环语句

​ Shell支持多种循环结构,包括常用的for、while,还有until

for循环

for循环语法

for var in list 
do 
	循环语句
done
# var循环变量
# list元素组合 通常是数组变量

​ 在执行for循环时,每次循环过程都将list中的相应位置的元素赋值给var,之后执行do…done之间的循环语句。var变量的值可以在循环语句中使用

while循环

​ 理论上,for循环能够实现的while循环基本可以实现。

while语法

while 表达式 # 表达式为条件测试,测试结果为真执行循环语句,结果为假不执行.注意避免死循环
do
	循环语句
done

​ 如果表达式的结果一直为真,那么会一直执行,除以避免死循环

until循环

​ until循环时条件测试为假时才执行。

语法

until 表达式 # 表达式为假时,执行do...done循环语句
do 
	循环语句
done 

select循环

select是一个可以和用户进行交互的循环结构,在命令行Shell中非常实用。select循环结构中数组和变量是必须的。

语法

select var in list 
do
	循环语句
done
# var 必须的变量,由用户输入
# list 数组

注意,select结构是死循环,需要使用break、exit或Ctrl+C组合键等方法退出脚本

image-20230204131435417

continue和break语句

​ continue结束本次循环

​ break结束整个循环

数组

定义数组

​ 和变量的定义类似。在定义数组时,可以先声明用declare -a 数组,也可以不声明。

image-20230204115050218

image-20230204115103509

获取数据长度

​ Shell中使用#操作符来获取数组的长度,可以使用两种方法进行获取。

语法

# 查看整个数组长度
${#array[@]}
${#array[*]}
# 查看变量长度
${#x}
# 查看数组中一个元素的长度
${#array[n]}

数组切片

​ 数组切片是获得数组中的部分元素。

语法

array1=${array[@]:m:n}  # 获得原始array数组从m开始的n个元素
array1=${array[*]:m:n}  

m和n可以忽略,可正可负。

image-20230204122010446

注意,在赋值时,注意销毁之前定义的重名变量。不然会出错

数组字符串替换

​ 通常,在数组中修改元素值,需要重新赋值。而在Shell中提供了一种简单的方式来替换数组元素中的字符串。

语法

${array[@]/from/to}
${array[@]/from/}

​ array是要替换元素的数组名称;from是数组元素中原来存在的字符串;to是需要替换的新的字符串。如果没有to参数,则删除from指定的内容。

关联数组

​ Shell中还有一种被称为关联数组的数组形式。普通数组使用数字作为索引,而关联数组的Index使用字符串作为索引,通过索引与值一一相对应。

语法

ass_array=( [index]=vall [index=val2])
# ass_array是关联数组的数组名称

函数

​ Shell支持函数的创建与调用,当脚本过于复杂时,可以提取程序的某些功能,形成一个函数模块,通过函数调用实现某个功能。

函数定义

语法

function 函数名()
{
	函数体
}

函数的参数

​ 函数的函数体内可以通过$n的形式来获取参数的值。

​ 除了传递进来的参数,每个函数还有一些内部参数。常见内部参数如下表:

#    # 传递到脚本的参数个数
*    # 以一个单字符串显示所有向脚本传递的参数
$    # 脚本运行时的当前进程ID号
!    # 后台运行的最后一个进程ID号
@    # 与*号相同,但是使用时加引号,并在引号中返回参数个数
-    # 显示Shell使用的当前选项 
?    # 显示最后命令的退出状态

脚本中传递参数语法

function 函数名()
{
	$1
	$2
}
函数名 参数1 参数2 # 在这里传入参数

函数的返回值

​ 在Shell编程中,每个函数都会有返回值。如果没有自定义返回值,那么会以最后一条命令执行结果作为返回值;如果用户自定义返回值,可以在函数的最后添加return n(n in [0-255]),

文本处理

格式化输出

​ 格式化输出能够把输出的内容根据指定的格式输出,自动对齐、换行等操作。格式化输出内容使用的是printf指令。

语法

printf format-string [arguments…]
# format-string 格式化字符串操作
# [arguments…] 参数字符串,待输出美容

注意】转义字符只在格式字符串中会被特别对待,出现在参数字符串里的转移字符不会被解释、

常见格式化字符如下

\t  # 水平tab 键
\v  # 垂直tab 键
\n  # 换行
\r  # 回车, Enter键
\f  # 清除屏幕
\b  # 输出退格键
\a  # 输出警告声音
%ns    # 输出字符串: 输出n位的字符串
%ni    # 输出整数: 输出n位的整数
%m.nf  # 输出浮点数: m位整数 和 n位小数

sed命令 未看

​ sed处理替换文本的需求。如,某个词首字母大写。

​ sed可以进行替换、删除、新增、选取等特定工作,sed命令常用选项及操作如下。

-n  # 使用安静模式
-e  # 直接在命令列模式上进行编辑 
-f  # 将sed命令输出到文件中,通过执行该文件执行对应的sed命令

awk命令 未看

diff文本内容比较

​ diff语法

diff ver1 ver2

​ 其中,ver1和ver2是相同的恩建,但是版本不同。对比结果会输出到终端中,也可以使用重定向的方式,将结果输出到指定文件中,形成修补文件。

`