目录
前言
一些命令序列是需要反复调用执行的,若每次使用同一命令就重复写一遍,就会导致代码量很
大,行数特别多。为解决该问题可以将命令序列按格式写在一起,以便可以重复的使用。
一、shell脚本调试
1、echo命令及转义符含义
◆echo -n 表示不换行输出
◆echo -e 输出转义符,将转义后的内容输出到屏幕上
常用转义符:
◆\b 转义后相当于按退格键(backspace) ,但前提是"b"后面存在字符; "\b"表示删除前一个字符,
"\bb"表示删除前两个字符。
◆\c 不换行输出,在"\c"后面不存在字符的情况下,作用相当于echo-n;但是当"\c"后面仍然存在字符
时, "\c"后面的字符将不会被输出。
◆\n 换行,被输出的字符从"\n"处开始另起一行
◆\f 换行,但是换行后的新行的开头位置连接着上一行的行尾;
◆\v 与\f相同
◆\t 转以后表示插入tab,即横向制表符;
◆\r 光标移至行首,但不换行,相当于使用"\r"以后的字符覆盖"1r"之前同等长度的字符;但是当"r"后面
不存在任何字符时, "\r"前面的字符不会被覆盖
◆\\ 表示插入""本身
2、bash命令
命令格式:sh [-nvx] 脚本名
bash常用参数的具体含义为:
◆ -n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任 何内容,如果有问题会提示报错。
◆ -v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也 会给出错误提示。
◆-x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数。 当脚本文件较长时,可以使用 set 命令指定调试一段脚本。
3、set命令
◆set -X 开启调节模式
◆set +x 关闭调节模式
二、shell函数
1、函数简介
Shell函数定义的基本格式如下
其中[function]是可选的,表示该函数的功能,这个是可以省略掉的;函数名后面加一个
(),里面是没有内容的;而我们执行的命令序列放在{ }里面的,[return x]的作用是当命令序列执
行完后返回给系统一个值,该项也是可以省略的。函数定义完成后并不会自动执行,在脚本中调用
函数的方式是直接输入函数名即可,有时候还需要输入一些参数。
[root@kang mytext]# vim hanshuxx.sh
#!/bin/bash
function fun1 {
echo "this is a function" #简单的函数创建
}
fun1 #函数调用
2、函数返回值
return表示退出函数并返回一个退出值,脚本中可以用$?变量显示该值。
使用原则:
①、函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码。
②、退出状态码必须是0~255,超出时值将为除以256取余。
[root@kang mytext]# vim hanshuxx.sh
#!/bin/bash
function test {
read -p "请输入数字:" num
return "$[$num*2]"
}
test
echo $?
[root@kang mytext]# bash test1.sh
请输入数字:2
4
[root@kang mytext]#
3、函数传参
传参就是向函数传递参数,
[root@kang mytext]# vim test1.sh
#!/bin/bash
sum () {
read -p "请输入第个参数:" NUM1
read -p "请输入第二个参数:" NUM2
echo "你输入的两个数为:$NUM1和$NUM2"
SUM=$(( $NUM1+$NUM2 ))
echo "两个数的和为: $SUM"
}
sum
[root@kang mytext]# bash test1.sh
请输入第个参数:12
请输入第二个参数:31
你输入的两个数为:12和31
两个数的和为: 43
[root@kang mytext]#
4、shell函数变量的作用范围
函数在Shell脚本中仅在当前Shell环境中有效,Shell脚本中变量默认全局有效,将变量限定在
函数内部使用local命令即可。函数内是局部 函数外是全局。
[root@kang mytext]# vim test1.sh
#!/bin/bash
fun () {
local a
a=5
echo $a
}
a=9
fun
echo $a
[root@kang mytext]# bash test1.sh
5 #函数里面定义的5只在函数里有效
9, #而函数外的$a还是之前最开始定义的9
上述脚本中fun函数内部使用了local命令设置变量a,其作用是将变量a限定在函数内部。fun
函数外部同样定义了变量a,内部变量a和全局变量a互不影响。脚本执行时先调用了函数fun,函数
内部变量a为5,所以输出结果是5。调用完函数之后,给变量a赋值为9,再打印外部变量a,所以
又输出9。
5、函数其他应用
①、函数目录递归
函数自己调用自己本身。列出目录内文件列表,目录用蓝色表示,文件显示层级关系。
[root@kang mytext]# vim hanshuxx.sh
#!/bin/bash
list () {
for a in $1/* #遍历目录
do
if [ -d $a ]
then
#判断若为目录则按格式输出目录名称并继续调用函数遍历这个目录
echo -e "\e[34m$a\e[0m"
list $a "$2"
else
#判断为文件则直接按照格式输出文件名称
echo "$2$a"
fi
done
}
list "/mytext/" ""
##调用函数,第一个参数为要进行遍历的目录,第二个参数为格式设定,区分目录层级
[root@kang mytext]# bash linshi.sh
/mytext//20210911-01.sh
/mytext//20210911-ftp.sh
/mytext//aa #此处目录显示为蓝色,
/mytext//aa/a.txt #其它文件显示层级关系
/mytext//aa/b.txt
/mytext//DNS_xx.sh
/mytext//first.sh
/mytext//forxx.sh
…………
②、函数的阶乘
正整数的阶乘是所有小于及等于该数的正整数的积,并且0的阶乘为1。阶乘是一个递推定
义,n!=n*(n-1)!;人为规定,因为1!=1,根据1!=1*0!,所以0!=1而不是0。
[root@kang mytext]# vim hanshuxx.sh
#!/bin/bash
fa ()
{
if [ $1 -eq 1 ];then echo 1
else
local tp=$[ $1 - 1 ]
local res=$(fa $tp)
echo $[ $1 * $res ]
fi
}
read -p "请输入阶乘起始值:" num
res=$(fa $num)
echo $res
[root@kang mytext]# bash linshi.sh
请输入阶乘起始值:5
120
[root@kang mytext]#
三、shell数组
数组是存放相同类型数据的集合。在内存中开辟了连续的空间,通常配合循环使用。
1、数组的分类:
普通数组:不需要声明直接定义,下标索引只能是整数
关联数组:需要用declare -A声明,否则系统不识别,索引可以是字符串
2、数组的定义方式
①、第一种:直接把要加入数组的元素用小括号括起来,中间用空格分开。
[root@kang ~]# num=(11 22 33 44)
[root@kang ~]# echo ${num[@]}
11 22 33 44
数组名= (value0 value1 value2)
②、第二种:精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续。
[root@kang ~]# num=([0]=55 [1]=66 [2]=77 [4]=88)
[root@kang ~]# echo ${num[@]}
55 66 77 88
[root@kang ~]#
数组名=([0]=value [1] =value [2] =value...)
③、第三种:先把要加入数组的元素全部先赋值给- 一个变量,然后引用这个变量加入到数组。
[root@kang ~]# list="10 16 30 40 50"
[root@kang ~]# num=($list)
[root@kang ~]# echo ${num[@]}
10 16 30 40 50
[root@kang ~]#
④、第四种:使用变量名加索引,给索引所在位置赋值。
[root@kang ~]# num[0]=2
[root@kang ~]# num[1]=5
[root@kang ~]# num[4]=6
[root@kang ~]# num[5]=7
[root@kang ~]# echo ${num[@]}
2 5 6 7
[root@kang ~]#
3、数组应用场景
[root@kang ~]# echo ${num[@]} #获取数据列表
2 5 6 7
[root@kang ~]# echo ${num[*]} #获取数据列表
2 5 6 7
[root@kang ~]# echo ${#num[@]} #加#号获取数组长度
4
[root@kang ~]# echo ${num[1]} #读取某索引对应的赋值
5
[root@kang ~]# echo ${num[@]:0:2}
2 5
[root@kang ~]# echo ${num[@]:1:2} #显示从第1个索引下标开始往后的两位
5 6
#数组切片,第一个冒号后跟的是索引号;第二个冒号后跟的为长度
[root@kang ~]# echo ${num[@]/5/9} #将数组中元素5替换成元素9
2 9 6 7
[root@kang ~]# echo ${num[@]} #紧接着查看数组原来的元素
2 5 6 7
#注意:这里替换是临时的,不会影响原数组元素
[root@kang ~]# unset num[4] #unset加上索引会删除下标对应赋值
[root@kang ~]# echo ${num[@]}
2 5 7
[root@kang ~]# unset num #删除整个数组
[root@kang ~]# echo ${num[@]}
[root@kang ~]#
数组遍历
[root@kang mytext]# vim shuzu.sh
#!/bin/bash
arr=(1 2 3 4 5 6) #定义一个数组
for a in "${arr[@]}" #遍历循环数组中的元素
do
echo $a
done
for a in "${arr[*]}" #这里可以比较@和*的区别
do
echo $a
done
[root@kang mytext]# bash shuzu.sh
1
2
3
4
5
6 #当使用@时,数组中元素是单独的个体
1 2 3 4 5 6 #当使用*号时,数组显示出来的元素是一个整体
四、冒泡排序
1、冒泡排序基本思想
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素
移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就
像气泡一样从底部上升到顶部。
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1
次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环
主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减
少。
2、冒泡排序算法应用
[root@kang mytext]# vim paixu.sh
#!/bin/bash
###############冒泡排序从小到大排.........................
arr=(90 70 50 60 30 40) #定义数组
echo "array:${arr[*]}" #显示数组
lt=${#arr[*]} #将数组长度显示并赋值给lt
for ((i=1;i<$lt;i++)) #定义第一个数比较总轮数比数组长度小.从第一轮开始即i=1
do
#确定比较元素得位置,比较相邻两个元素,较大得数往后放,小的数前放,并且每轮比较次数要随着轮>数递减。
for ((j=0;j<$lt-i;j++)) #定义每次比较后元素的下标
do
first=${arr[$j]} #定义第一个元素的值;第一次下标为0的数赋值给第一个变量
k=$[$j+1] #关联第一个下标,比第一个下标多1位
second=${arr[$k]} #定义第二个元素的值;前一位数的后一位数赋值给第二个变量
#若第一个元素比第二个元素大,就互换位置
if [ $first -gt $second ];then #比较两个变量的大小
tmp=$first #添加临时变量,把大的值赋值给临时变量名
arr[$j]=$second #把小的值赋值给数组下标小的
arr[$k]=$tmp #把临时变量(大的值)值赋值给下标+1位对应值
fi
done
done
echo "new-array:${arr[*]}"
[root@kang mytext]# bash paixu.sh
array:90 70 50 60 30 40
new-array:30 40 50 60 70 90
[root@kang mytext]#
总结
未完待续。