目录
一、shell函数
1、什么是shell函数
■将命令序列按格式写在一起
■可方便重复使用命令序列
2、格式
格式1:
function 函数名 {
command
} #规范写法
格式2:
函数名(){
command
} #一般最常用,因为最简洁
3、函数的调用
#!/bin/bash
function f1 { #定义一个函数叫f1
echo hello #函数的功能是打印hello
}
f1 #直接写函数名就会运行函数内的代码
f2() { #定义一个函数叫f2
echo world #函数的功能是打印world
}
f2
注意:
1、函数名必须是唯一,如果先定义了一个,再用同样的名称定义,第二个会覆盖第一个的功能,出现了你不想要的结果,所以这里一定要注意不要重名!
2、函数调用是从上到下的。
例子
安装本地yum源
[root@ky19cl hanshu]# vim bdyum.sh
#!/bin/bash
function backuprepo {
cd /etc/yum.repos.d
mkdir repo.bak
function backuprepo {
cd /etc/yum.repos.d
mkdir repo.bak
mv *.repo repo.bak
mount /dev/sr0 /mnt > /dev/null
}
makelocalrepo(){
echo '[local]
name = local
baseurl=file:///mnt
enabled=1
gpgcheck=0' > local.repo
}
uselocalrepo(){
yum clean all > /dev/null
yum makecache > /dev/null
yum install -y httpd > /dev/null
}
#调用
backuprepo
makelocalrepo
uselocalrepo
4、函数的返回值
return表示退出函数并返回一个退出值,脚本中可以用$?变量表示该值
函数的使用原则:
1、函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码;
2、退出状态码必须是0~255,超出时值将为除以256取余。
#!/bin/bash
test1(){
read -p "请输入一个数:" num
return $[$num]
}
test1
echo $?
#!/bin/bash
file=/home/for/
test1(){
if [ -f $file ];then
return 80
else
return 40
fi
}
test1
5、函数的传参
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…即使用位置参数来实现参数传递。
#!/bin/bash
sum(){
read -p "请输入第一个数:" num1
read -p "请输入第二个数:" num2
echo "第一个数和第二个数求和:$num1和$num2 "
sum=$[$num1 + $num2]
echo $sum
}
sum
位置参数例子(执行脚本时加参数)
#!/bin/bash
#add(){
#let sum=$1+$2
#echo $sum
#}
#add 4 5
#add $1 $2
test1 (){
rm -rf $1
}
test1 /home/for/a.txt
阶乘
1、无交互
#!/bin/bsah
jc(){
cl=1
for i in {1..6}
do
let cl=$i*$cl
done
echo $cl
}
jc
2、有交互
#!/bin/bash
jc () {
che=1
read -p "请输入您想算的阶乘:" num
for i in `seq $num`
do
let che=$i*$che
done
echo $che
}
jc
6、本地变量与全局变量-local
- 在脚本里定义的变量或者在函数体没有声明为本地变量的都为全局变量,意思是在当前shell环境都识别
- 如果需要这个变量只在函数中使用则可以在函数中用local关键字声明,这样即使函数体外有个重名的变量也没关系,不影响在函数体的使用
#!/bin/bash
myfun(){
local i
i=6
echo $i
}
i=8
myfun
echo $i
7、函数的递归
定义:函数自己调用自己的本身
例子
列出目录内文件列表,目录用蓝色表示,文件显示层级关系
#!/bin/bash
list(){
for i in $1/*
do
if [ -d $i ];then
echo -e "\e[34m$i\e[0m"
list $i " $2"
else
echo "$2$i"
fi
done
}
list $1 $2
阶乘递归
#!/bin/bash
#计算你输入的阶乘
fun (){
if [ $1 -eq 1 ];then
echo 1
else
local tp=$[$1 - 1 ]
local res=$(fun $tp)
echo $[$1 * $res ]
fi
}
read -p "请输入数字;" num
res=$(fun $num)
echo $res
二、数组
1、数组的定义
数组是存放相同类型数据的集合,在内存中开辟了连续的空间,通常配合循环使用
2、数组的分类
普通数组:不需要声明直接定义,下标索引只能是整数
关联数组:需要用declare -A声明否则系统不识别,索引可以是字符串
3、数组的定义方式
第一种:直接把要加入数组的元素用小括号括起来,中间用空格分开
num=(11 22 33 44)
num= ( 11 22 33 44 )
${ #num} 显示字符串长度
数组名=(value0 value1 value2)
第二种:精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续
num=([0]=55 [1]=66 [2]=77 [4]=88)
num= ( [ 0 ]=55 [ 1 ]=66 [ 2 ]=77 [ 4 ]=88)
数组名=( [ 0 ]=value [ 1 ]=value [ 2 ]=value. . . )
第三种:先把要加入数组的元素全部先赋值给一个变量,然后引用这个变量加入到数组
list=“11 12 13 14”
num=($list)
列表名="value0 value1 value2..."
数组名=($列表名)
第四种:可以把命令的结果用小括号括起来添加到数组,那么数组会以空格或者制表符区分每一个元素
num=(`cat /etc/passwd`)
[root@localhost ~]# echo ${#num[*]}
111
[root@localhost ~]# echo ${num[0]}
root:x:0:0:root:/root:/bin/bash
注意以下特殊方式:
[root@localhost ~]# list[0]=1 //没有定义数组之前也可这样直接定义元素
[root@localhost ~]#
[root@localhost ~]# echo ${list[*]}
1
[root@localhost ~]# list=([0]=1 [1]=2 [3]=4) //定义数组时所以可以是不连续的
[root@localhost ~]# echo ${list[*]}
1 2 4
[root@localhost ~]# echo ${!list[*]} //没有2这个索引,数组元素为3
0 1 3
[root@localhost ~]# ff=(1 2 zhangsan lisi) //不是同一数据类型的也可定义为一个数组
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# echo ${ff[*]}
1 2 zhangsan lisi
4、数组常见用法
1、读取数组和元素
[root@localhost ~]# fruit=(apple banana orange) //定义了一个水果的数组
[root@localhost ~]# echo ${#fruit[*]} //查看这个数组元素的个数,也是数组长度
3
[root@localhost ~]# echo ${!fruit[*]} //查看这个数组元素的索引
0 1 2
[root@localhost ~]# echo ${fruit[*]} //查看这个数组的元素
apple banana orange
[root@localhost ~]# echo ${fruit[@]} //查看这个数组的元素
apple banana orange
[root@localhost ~]# echo ${fruit[0]} //查看这个数组索引为0的元素
apple
[root@localhost ~]# declare -a | grep fruit //查看声明的所有变量可以看到数组
declare -a fruit='([0]="apple" [1]="banana" [2]="orange"
2、元素切片
[root@localhost ~]# arr=(1 2 3 4 5 6 7 8)
[root@localhost ~]# echo ${arr[*]:2:3} //提取从索引2开始的3个元素
3 4 5
[root@localhost ~]# echo ${arr[*]:2:2}
3 4
[root@localhost ~]# echo ${arr[*]:0:2}
1 2
3、定义某一个元素
[root@localhost ~]# fruit[0]=pear
[root@localhost ~]#
[root@localhost ~]# echo ${fruit[*]}
pear banana orange
4、元素替换
定义或替换某一个元素
[root@localhost ~]# fruit[0]=pear
[root@localhost ~]#
[root@localhost ~]# echo ${fruit[*]}
pear banana orange
[root@localhost ~]# echo ${fruit[*]/banana/ba} //临时替换
pear ba orange
[root@localhost ~]# echo ${fruit[*]}
pear banana orange
5、元素删除
[root@localhost ~]# unset fruit[0]
[root@localhost ~]#
[root@localhost ~]# declare -a | grep fruit
declare -a fruit='([1]="banana" [2]="orange")'
6、数组删除
[root@localhost ~]# unset fruit
5、冒泡排序
-
什么是冒泡排序
类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动 -
基本思想
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部 -
算法实现
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。
#!/bin/bash
arr=(90 70 80 100 30 66)
echo "old_arr:${arr[*]}"
lt=${#arr[*]}
#定义比较轮数,轮数为数组长度-1,从1开始
for ((i=1;i<$lt;i++))
do
#确认比较元素的位置,比较相邻的元素,较大的往后移,比较次数随比较轮数减少
for ((j=0;j<$lt-1;j++))
do
#定义第一个元素的值
first=${arr[$j]}
#定义第二个元素的值
k=$[$j+1]
second=${arr[$k]}
#如果第一个元素比第二个大就互换位置
if [ $first -gt $second ];then
#把第一个元素保存到临时变量中
temp=$first
#把第二个元素的赋值给第一个元素
arr[$j]=$second
#把临时变量赋值给第二个元素
arr[$k]=$temp
fi
done
done
echo "new_arr:${arr[*]}"
总结
在生产上函数使用的是非常多的,调用函数是非常方便的,有利于我们提高工作效率。基本数组使用方法也是非常实用的。