shell脚本之until语句、函数和数组
一、until语句
1.1until语句结构
重复测试某个条件,只要条件不成立则反复执行
until 条件测试操作
do 命令序列
done
1.2until语句的应用
1.2.1通过循环累加的方式计算1-100的和
[root@localhost ~]# vim sum50.sh
#!/bin/bash
i=1
S=0
until [ $i -gt 100 ]
do
let S+=$i
let i++
done
echo "$S"
[root@localhost ~]# sh sum50.sh
5050
1.2.2 为制定用户发在线消息
具体要求
- 若指定用户不在线(未登陆系统),则每5S试一次,直至用户登录系统后再发送信息
- 用户名与消息通过为止参数传递给脚本
#!/bin/bash
username=$1
if [ $# -lt 1 ];
then
echo "usage:`basename $0` <username> [<message>]"
exit
fi
if grep "^$username" /etc/passwd &> /dev/null;then :
else
echo "not user"
exit 2
fi
until who | grep "$username" &> /dev/null;do
echo "user not login"
sleep 5
done
echo "$2"|write "$username"
echo "${username}发送成功
[root@localhost ~]# vim hello.sh
[root@localhost ~]# sh hello.sh
usage:hello.sh <username> [<message>]
[root@localhost ~]# sh hello.sh lisi
not user
[root@localhost ~]# sh hello.sh liu
[root@localhost ~]# sh hello.sh liu
user not login
user not login
user not login
u[root@localhost ~]# sh hello.sh liu
liu发送成功ser not login
二、函数
2.1shell函数概述
- shell一个非常重要的特性是它可作为一种编程语言来使用。
- 因为shell是一个解释器,所以它不能对为它编写的程序进行编译,而是在每次从磁盘加载这
- 程序时对它们进行解释。而程序的加载和解释都是非常耗时的。
- 针对此问题,许多shell(如BourneAgainShell)都包含shell函数,shell把这些函数放在内存中,这样每次需要执行它们时就不必再从磁盘读入。
- shell还以一种内部格式来存放这些函数,这样就不必耗费大量的时间来解释它们
- shell函数将命令序列按格式写在一起
- 可以方便重复使用命令序列
2.2shell函数定义
[fuction ] 函数名(){
命令案例
[return x]
使用return或者exit可以显示的结束函数
return返回的是状态码,需要使用$?调取
echo 返回的是值,使用变量调用
传参:指位置变量
可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。
2.3:调用函数的方法
函数名 [参数1($1)] [参数2($2)]
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,
2
表
示
第
二
个
参
数
…
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
。
当
n
>
=
10
时
,
需
要
使
用
2表示第二个参数… 10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要 10 不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用
2表示第二个参数…10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要10。当n>=10时,需要使用{n}来获取参数。
2.4:shell函数应用
-
两个数字求个
通过sum(){}定义函数
使用read命令交互输入两个数并求和
#!/bin/bsah
function sum () {
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$[$num1+$num2]
echo "和:$SUM"
}
sum
或者
#!/bin/bsah
function sum () {
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=`expr $num1 + $num2 `
echo "和:$SUM"
}
sum
或者
function sum () {
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$(($num1+$num2))
echo "和:$SUM"
return 100
}
sum 调用上面的函数体
echo $? 输出的是return 返回值100
末尾sum是函数名,作用是调用整个函数体
[root@localhost ~]# sh sum.sh
请输入第一个整数;12
请输入第二个整数;18
和:30
100
下面两个echo $?对比
#!/bin/bsah
function sum () {
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$(($num1+$num2))
echo "和:$SUM"
return 100
}
number=`sum ` sum是echo返回值“和:$SUM"
echo $? 输出的是上一条命令“ number=`sum ` ”状态码100
“ number=`sum ` ”是调用上面的函数体所有状态码和函数体状态码一样
echo $number
[root@localhost ~]# sh sum.sh
请输入第一个整数;12
请输入第二个整数;18
100
和:30
#!/bin/bsah
function sum () {
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$(($num1+$num2))
echo "和:$SUM"
return 100
}
number=`sum`
echo $number
echo $? echo 输出的是上一条命令“echo $number"的执行状态码
[root@localhost ~]# sh sum.sh
请输入第一个整数;12
请输入第二个整数;18
和:30
0 0表示“echo $number"正常执行
2.5函数的参数
2.5.1函数的用法
函数名称 参数1 参数2 参数3
2.5.2参数的表示方法
$1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}…
2.5.3示例
参数求和
#!/bin/bsah
function sum () {
SUM=$(($1+$2))
echo "$SUM"
return 100
}
number=`sum 10 20`
let number+=1
echo $number
[root@localhost ~]# vim sum.sh
[root@localhost ~]# sh sum.sh 10 20
31
2.5.4local定义局部变量
#!/bin/bsah
function sum(){
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$[$num1+$num2]
echo "$SUM"
score=100
echo "函数内$score"
}
sum
echo "函数外$score"
[root@localhost ~]# sh sum.sh 10 20
请输入第一个整数;10
请输入第二个整数;20
30
函数内100
函数外100
#!/bin/bsah
function sum(){
read -p"请输入第一个整数;" num1
read -p"请输入第二个整数;" num2
SUM=$[$num1+$num2]
echo "$SUM"
local score=100
echo "函数内$score"
}
sum
echo "函数外$score"
~
[root@localhost ~]# vim sum.sh
[root@localhost ~]# sh sum.sh 10 20
请输入第一个整数;10
请输入第二个整数;20
30
函数内100
函数外
local定义后只在函数体内生效,函数体外不生效
2.5递归函数
调用自己本身的函数
示例
递归遍历目录
通过定义递归函数list_files来实现
#!/bin/bash
function list_files(){
for f in `ls $1`
do
if [ -d "$1/$f" ];then
echo "$2$f"
list_files "$1/$f" " $2"
else
echo "$2$f"
fi
done
}
list_files "/var/log" " "
~
~
[root@localhost opt]# sh digui.sh
anaconda
anaconda.log
ifcfg.log
journal.log
ks-script-B2lEaV.log
packaging.log
program.log
storage.log
syslog
X.log
audit
audit.log
三、数组
3.1数组的概念
3.1.1数组:
放置相同类型数据的集合 [11,12,22,33,44]
数组实际是在内存中开辟了连续的空间
往往配合循环一起使用
3.1.2数组构成
数组名称 bac=(11,22,33,44)
数组元素11,22,33,44
数组的长度即数组元素个数
3.1.3数组下标
bac=(11,22,33,44)
0 1 2 3
3.2数组的类型
- 数值型
- 字符型
3.3数组的定义方法
3.3.1方法一
数组名= (元素1 元素2 元素3 元素4)
[root@localhost ~]# num=(11 22 33 44 55)
[root@localhost ~]# echo ${num[*]} num 是数组名 *是代表数组的所有下标
11 22 33 44 55
3.3.2方法二
数组名= ([0]=元素1 [1]=元素2 [3]=元素3 [3]=元素4)
[root@localhost ~]# num=([0]=66 [1]=77 [2]=88 [3]=99)
[root@localhost ~]# echo ${num[*]}
66 77 88 99
[root@localhost ~]# echo ${num[@]} *和@作用一样
66 77 88 99
3.3.3方法三
先定义给列表,再把列表元素赋予给数组
列表名=“元素1 元素2 元素3 元素4”
数组名=($列表名)
[root@localhost ~]# list="1 2 3 4"
[root@localhost ~]# num=($list)
[root@localhost ~]# echo ${num[*]}
1 2 3 4
3.3.4方法四
数组名[0]=“元素"
数组名[1]=“元素
数组名[2]=“元素
主要用于替换,替换其中的元素
[root@localhost ~]# echo ${num[*]}
1 2 3 4
[root@localhost ~]# num[1]=80
[root@localhost ~]# echo ${num[*]}
1 80 3 4
3.3示例
3.3.1示例1
创建1-100的数组
#!/bin/bash
for ((i=0;i<=99;i++));do
list[$i]=$[$i+1]
done
echo ${list[*]}
[root@localhost ~]# sh 100.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
3.3.2示例2
创建存放1-100奇数数组
#!/bin/bash
for ((i=0;i<=99;i+=2));do
list[$i]=$[$i+1]
done
echo ${list[*]}
[root@localhost ~]# sh 100.sh
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99
方法二
#!/bin/bash
k=0
j=1
for ((i=0;i<=99;i+=1));do
k=$[$i+$j]
let j++
if [ $k -le 100 ];then
jishu[$i]=$k
fi
done
echo ${jishu[*]}
3.3.3示例3
创建任意数字及长度的数组,根据客户需求加入元素
#!/bin/bash
i=0
while true
do
read -p"是否存入元素(yes/no):" choose
if [ $choose == "no" ];then
break
fi
read -p "请存入第$[$i+1]个元素;" key
num[$i]=$key
let i++
done
echo ${num[*]}
[root@localhost ~]# sh test05.sh
是否存入元素(yes/no):yes
请存入第1个元素;22
是否存入元素(yes/no):yes
请存入第2个元素;77
是否存入元素(yes/no):yes
请存入第3个元素;88
是否存入元素(yes/no):yes
请存入第4个元素;45
是否存入元素(yes/no):no
22 77 88 45
3.4数组操作长度
${数组名[*/@]}
[root@localhost ~]# echo ${a[*]}
1 2 3 4 5
[root@localhost ~]# b=${#a[*]}
[root@localhost ~]# echo $b
5
3.5数组遍历
格式
for 变量 in 数组
do
echo $变量
done
[root@localhost ~]# for v in ${a[*]} > do > echo $v > done > 1 > 2 > 3 > 4 > 5
3.5.1示例1
将数组中小于60的数变为60
#!/bin/bash
score=(40 50 59 60 70 80)
for ((i=0;i<${#score[*]};i++));do
if [ ${score[i]} -lt 60 ];then
score[$i]=60 直接将下标对应的元素替换
fi
done
echo ${score[*]}
[root@localhost ~]# sh test06.sh
60 60 60 60 70 80
方法二
#!/bin/bash
score=(40 50 59 60 70 80)
for ((i=0;i<${#score[*]};i++));do
if [ ${score[$i]} -lt 60 ];then
new[$i]=60
else
new[$i]=${score[$i]}
fi
done
echo ${new[*]}
3.5.2示例2
找出数组中最大的数值
#!/bin/bash
score=(40 50 59 60 70 80)
a=0
for ((i=0;i<${#score[*]};i++));do
if [ ${score[$i]} -gt $a ];then
a=${score[$i]}
fi
done
echo $a
[root@localhost ~]# sh test06.sh
80
3.5.3示例3
降序排列
#!/bin/bash
score=(40 50 59 60 70 80)
for ((i=0;i<${#score[*]};i++));do
for((j=i+1;j<${#score[*]};j++));do
if [ ${score[$i]} -lt ${score[$j]} ];then
let a=${score[$j]}
let score[j]=${score[$i]}
let score[i]=a
fi
done
done
echo ${score[*]}
[root@localhost ~]# sh test06.sh
80 70 60 59 50 40
3.6数组切片
示例删除小于60的元素
#!/bin/bash
score=(55 66 77 44 88)
for((i=0;i<${#score[*]};i++));do
if [ ${score[i]} -lt 60 ];then
unset score[i]
fi
done
echo ${score[*]}
上面这种方法看似正确,实际上有问题。因为在删除数组元素后,数组长度就出现了变化,肯会读不到对应的元素
下列方法能更准去的定位要删除的元素
#!/bin/bash
score=(55 66 77 44 88)
i=0
for v in ${score[*]};do
if [ $v -lt 60 ];then
unset score[$i]
fi
let i++
echo ${#score[*]}
done
echo ${score[*]}
[root@localhost ~]# sh tes04.sh
4
4
4
3
3
66 77 88
];then
let a=KaTeX parse error: Expected '}', got 'EOF' at end of input: {score[j]}
let score[j]=KaTeX parse error: Expected '}', got 'EOF' at end of input: {score[i]}
let score[i]=a
fi
done
done
echo ${score[*]}
[root@localhost ~]# sh test06.sh
80 70 60 59 50 40
### 3.6数组切片
示例删除小于60的元素
#!/bin/bash
score=(55 66 77 44 88)
for((i=0;i<${#score[]};i++));do
if [ ${score[i]} -lt 60 ];then
unset score[i]
fi
done
echo ${score[]}
上面这种方法看似正确,实际上有问题。因为在删除数组元素后,数组长度就出现了变化,肯会读不到对应的元素
下列方法能更准去的定位要删除的元素
#!/bin/bash
score=(55 66 77 44 88)
i=0
for v in ${score[]};do
if [
v
−
l
t
60
]
;
t
h
e
n
u
n
s
e
t
s
c
o
r
e
[
v -lt 60 ];then unset score[
v−lt60];thenunsetscore[i]
fi
let i++
echo ${#score[]}
done
echo ${score[*]}
[root@localhost ~]# sh tes04.sh
4
4
4
3
3
66 77 88