开发者学堂课程【Linux Shell 编程:Linux Shell 训练营 Day2】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/856/detail/14109
Linux Shell 训练营 Day2
内容介绍
一、shell 脚本中数组的使用
二、shell 脚本中的循环控制
三、shell 脚本中的参数处理
四、shell 脚本中的函数
第二天主要学习数组,循环控制,参数处理,函数。本节课程内容较多,知识点的讲解不会面面俱到,只对重点知识点进行讲解,后面有视频课程详细讲解知识点。
一、shell 脚本中数组的使用
第一部分内容是数组的使用。在 shell 脚本中,如果需要编写比较复杂的代码会用到数组。
1.一维数组
(1)数组定义
数组使用一个圆括号括起来的,圆括号中的每一个元素建议放在双引号中,元素中的间隔使用空格,当圆括号中没有任何元素那么此数组定义为空数组。例如:my_array=(“aaa” “bbb” “ccc” “ddd”)
(2)元素引用
定义数组后进行引用,在 shell 中默认数组下标从0开始依次递增,增至数组长度减一为止。使用数组下标引用数组,例如数组名为 my_array,my_array 后使用方括号,方括号中填写数组下标即可获取数组中对应元素的值。
my_array=(“aaa” “bbb” “ccc” “ddd”)数组下标依次为0,1,2,3。进行元素引用时可以直接通过下标获取元素,同样也可以使用下标对数组中的值进行重新赋值,例如:my_array[0]=”eee” 将数组中第零个元素 赋值为 ”eee“与其他语言赋值方法类似,不同之处为数组声明方式。在引用数组中元素或对数组元素赋值时等号两边不能有空格。
输出数组元素值使用 符号$ ,符号$后使用花括号把元素括起来,与引用普通变量相似只是在引用数组时需要指定数组下标。例如 echo ${my_array[0]} 输出 my_array 数组中第零个元素,可以通过数组下标指定输出元素。
输出全部数组中所以元素时,在数组名后方括号中使用 *或 @ 符号,echo ${my_array[*]} 或echo ${my_array[@]}。
(3)数组长度
获取数组长度,例如 my_array=(“aaa” “bbb” “ccc” “ddd”)中定义四个元素在数组名 my_array 前加#,通过语法 echo ${#my_array[*]} 或 echo ${#my_array[@]}获取数组长度。
(4)数组分片
在 shell 中可以对数组分片,获取三个元素时在 my_array[@] 后跟:0:3,第一个冒号后数字表示起始下标从第零个元素开始,第二个冒号后数字表示分片中有几个数元素,从下标0开始有三个元素即可以取到三个元素,熟悉 python 的同学,会对此语法熟悉。需通过 echo ${my_array[@]:0:3}第一个数字表示从哪一个元素开始分片,第二个数字表示分片中有几个数元素。要练习熟悉数组定义,数组引用,以及数组长度的获取。
2.二维数组
(1)Shell 只有一维数组的概念,Shell 没有二维数组的概念
(2)如何实现二维数组的需求
如果一定需要使用二维数组,可以使用其他方式实现对二维数组的需求。
例如:
my_array=(
“a1” “a2” “a3”
“b1” “b2” “b3”
)定义数组名为 my_array,左括号与右括号可以换行,把多个元素,用多行表示一个数组。my_array 中定义六个元素,a1,a2,a3,b1,b2,b3,数组 my_array 是一维数组,把 a1,a2,a3放在同一行,把 b1,b2,b3放在同一行,从形式上看是二维数组概念。
使用二维数组方法与普通遍历相似,首先使用 len_ele_line=指定子数组长度,先遍历a1,a2,a3,再遍历 b1,b2,b3。
通过此操作可以把一维数组当作二维数组使用。len_ele_sum 表示整个数组的长度,len_ele_line=3 表示子数组长度。
二维数组的执行结果,a1,a2,a3是一个子数组;b1,b2,b3是一个子数组
3.关联数组(Bash 从4.0版本才支持)
第三部分关联数组其实是字典的概念,再 java 中也有字典的概念。在 shell 中4.0以上支持关联数组。使用 bash--version 查看版本号,在操作系统7.4上 bash 版本号为4.2.46(2)。现在大部分的操作系统上 bash 版本大部分在4.0以上。
(2)关联数组的定义与元素的访问
关联数组使用前必须使用 declare -A 提前声明,后面语法类似数组只是下标从数字变成字符串。
例如,declare -A color
color["read"]="#ff0000"
color ["blue"]="#000off"
co1or"b1ack"]="#000000"
可以通过 S{!color[@]} 获取关联数组的键值集合,通过遍历键值获取键值对。
(3)遍历元素的 key 和 value
二、shell 脚本中的循环控制
shell 脚本中的循环控制的使用即 for 语句的使用。通过对 for 语句的学习可以更加了解数组遍历。
1. for 语句
for 语法有两种:
(1)第一种
for var in list
do
commands
done
list 表示列表或者数组,var 是每一次遍历从list中取值,以 do 和 done 中包裹需要执行的命令。如果把 do,与 for var in list 放在同一行在 for var in list 后需要加上分号。
(2)第二种
for((变量赋值;迭代条件;迭代过程))
do
commands
done
2.读取列表中的值
例如:例一
for fruit in apple lemon orange
do
echo "This is $fruit"
done
echo "The last is $fruit"
变量 fruit 依次从列表 apple lemon orange 中读取,在每一次循环输出当前 fruit 变量内容即语句 This is $fruit,最后输出 fruit 变量内容即The last is $fruit。
前面 apple, lemon, orange 为一行,最后 fruit 值仍是 orange,说明 fruit 在循环结束后值有所保留与其他语言不同。原来为在 shell 中 fruit 作用域为全局,即在变量定义完成后即使后面对变量进行修改最后仍然可以获取变量最后修改的值。in 后面为列表,也能用数组,在 in 后面自定义数组,再引用。
例二,遍历文件中的内容
file="fruitlist.txt”
for fruit in $(cat ${file))
do
echo "This is $fruit"
done
fruitlist.txt 为文件名,再对文件编辑后,可以使用脚本读取并输出文件中内容。
cat 命令可以输出文件中内容,$()作用是命令执行,用$()获取命令执行后结果,把结果作为列表用 for 语句进行遍历,fruit 即为文件的每一行的内容。
3.用通配符遍历目录
使用通配符可以直接遍历 Linux 操作系统下每一个目录的所有文件。
例如,遍历 root 目录下所有文件
for file in /root/*
do
if [-f $file]
then
echo "file:$file"
elif [ -d sfil ]
then
echo "directory:$file"
fi
done
/root/*表示 root 下所有文件。用 /root/* 获取所以文件,遍历得到所有文件并判断文件是目录还是普通文件,如果是目录输出 directory,如果是普通文件输出 file。
执行结果,只有两个目录文件 Day1,Day2.如果创建一个普通文件 test ,再执行脚本可以获取 test 文件。
使用通配符通常用来遍历目录中文件。
(2)第二种
for((变量赋值;迭代条件;迭代过程))
Do
commands
done
与 C 语言类似,for 后用两个圆括号括起来,中间变量赋值,迭代条件,迭代过程与 C 语言类似。
例如,遍历数组下标
for((i=0;i<len_ele_sum;i<len_ele_sum));do
echo ${my_array[i]}
echo ${my_array[i+1]}
echo ${my_array[i+2]}
done
第二种 for 语句语法中,i=0,i<len_ele_sum,i<len_ele_sum 三段语句可以直接使用不需要在变量前添加符号$。脚本可以实现遍历数组下标的功能
2. while 语句
while 语句和 Until 语句是一般常用语言都有的。while 语句语法
用 do 和 done 把需要执行命令语句包围起来,其中可以添加多条语句;command 与前面 if 语句条件相同,可以理解为用方括号做条件判断;可以在 [ ]中添加判断段条件,如果满足判断条件然后执行 command1,command2直到不满做判断条件。
while [ ]
do
command1
command2
done
3. Until 语句
Until 语句与 while 语法类似,用 do 和 done 把需要执行的语句包围起来,其中可以添加多条语句,可以在 [ ]中添加判断段条件,until 语句是先执行 command1语句,command2语句 然后执行判断条件,如果满足判断条件退出循环语句。
方括号可以替换为 test 或 tses command 因为方括号本身是test的一种表达方式。Test command 是对 command返回值进行判断。
until [ ]
do
command1
command2
Done
4. 嵌套循环
For 语句,while 语句,unltil 语句可以进行嵌套循环,一般嵌套2到3层,如果嵌套太多语句结构复杂不容易理解。break 命令可以结束循环,一般与 if 语句套用,如果在 while 中增加 break 语句当满足某种判断条件时跳出循环,然后会执行 while 循环后的语句;continue 跳出当前循环进入下一个条件判断继续执行下一个循环语句,一般把 continue放在语句开始位置。
三、Shell 脚本的参数
如果执行 shift 语句 ,$1被移除然后$2,$3变量位置向前移动。例如有三个参数 a,b,c 执行 shift 语句后会删除参数 a,剩余参数 b,参数 c。
四、shell脚本中的函数
在编写较长脚本时又有重复语句,可以使用函数把重复语句进行封装,可以使得思维逻辑清晰,代码简洁便于他人观察。
1.创建函数
function func_name{...} 在创建函数是 function 可以省略
func_name(){...}
2.使用函数
func_name
在工作时比较常用函数:输出日志,在编写 shell 脚本时建议输出日志,每一步操作成功或者失败把日志输出,输出日志功能可以使用函数封装。例如,定义 log() 函数输出日志。log() 函数中输出当前日期和时间;用date命令获取当前日期和时间;参数 $1 $2,一般是定义一个参数的级别以及日志信息。需要输出日志时,调用 log 函数即可,log() 函数后传输日志级别及日期。使用 log() 函数输出日志格式规范,首先是日期然后是级别,对于以后日志的解析非常有帮助。
log(){
echo $(date +"F% %T")$1 $2
}
调用函数并传入参数 log "INFO" "message"
调用函数并传入参数 log "ERROR" "message"
创建函数语句 function func_name{...} ,在创建函数是 function 可以省略,func_name(){...}。使用函数时,调用函数名即可。需要传入参数,只需在调用函数名时在函数名后写入参数名即可。
在整个脚本和函数中使用参数使用方法类似,在整个脚本中定义一个参数,可以在脚本中对参数进行处理;对于函数来说,在函数名后面传入参数,在函数编写过程中可以对函数中参数进行处理;位置变量,参数个数,对参数处理shift 语句相同。
3.函数中使用变量
(1)向函数传递参数
(2)位置参数变量
4.在函数中处理变量
(1)全局变量
在 shell 脚本中的变量是全局的,在外面定义变量在函数中修改,变量名相同可以通过函数名在函数中进行修改。与其他语言不同,体现在变量作用域的区别
(2) 局部变量 local
使用局部变量在变量名前加上 local ,变量的作用域会局限在函数中。
例如,
val="value"
func(){
return 0
}
func
echo $val
输出结果为 value,当在函数中对 val 值进行修改则输出修改后的值,如果函数中在修改时在 val 前加上 local 命令则不会影响整个脚本中 val 变量的值,local 变量定义域在函数内部对于整个脚本中全局变量的值不产生影响。如果脚本复杂,变量名相同在函数中不要随意修改变量值。
5. 函数的返回值
(1)获取函数的退出代态码
(2)函数的返回值默认函数最后执行的命令的退出状态码与整个脚本的退出状态码相同。
可以使用 $? 命令来获取退出状态码
(3)使用 return 命令自定义返回值,支持返回一个0-255的整数。一般返回值为0 表示函数执行正常,返回1或者其他可以进行自定义一般认为函数执行有误,可以使用 if 条件判断进行处理。
(4)使用命令执行获取函数的输出,可以实现获取一个字符串。通过命令执行的方式把函数输出值赋值给变量,可以把返回结果赋值给变量然后进行使用。
例如,ans-$(func) 把返回值赋值给一个变量。
func(){
echo "cccc"
return 1
}
ans=$(func)
echo $ans
如果 func() 函数执行正常输出 ”aaa“,如果函数执行有无则输出”bbb“。如果返回字符串”ccc“,可以通过命令执行的方式把函数的输出赋值给变量 ans,然后输出变量 ans 即可获取函数返回的字符串。








