赞
踩
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件。循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体。 [1] 循环语句是由循环体及循环的终止条件两部分组成的。
函数也是具有和别名类似的功能。函数的作用就是把程序里多次调研相同的代码部分定义成一份,然后为这一份代码起个名字,其它所有的重复调用这部分代码都只用调用这个名字就可以。当需要修改这部分重复代码时,只需要改变函数体内的一份代码即可实现调用修改。
使用函数的优势:
1、把相同的程序段定义成函数,可以减少整个程序的代码量。
2、增加程序的可读性,以及便于管理。
3、可实现程序功能模块化,不同的程序使用函数模块化。
4、让程序代码结构更清晰。
读取不同的变量值,用来逐个执行同一组命令
语句结构
for 变量名 in 取值列表
do
命令序列
done
语句结构举例
for 收件人 in 邮件地址列表
do
发送邮件
done
用户名存放在users.txt文件中,每行一个
初始密码均设为123456 cd test [root@shanan test]# vim users.txt W1 W2 W3 W4 W5 ~ [root@shanan test]# vim user.sh #!/bin/bash users=`cat /test/users.txt` for user in $users do useradd $user > /dev/null echo "123456" | passwd --stdin $user > /dev/null done list=` cat /etc/passwd | awk -F: '{print $1}' ` echo "所有用户列表如下 $list" [root@shanan test]# sh user.sh 所有用户列表如下 .........省略 W1 W2 W3 W4 W5
检测IP地址192.168.100.0-192.168.100.10段落
使用ping命令检测各主机的连通性
[root@localhost opt]# vim ping.sh #!/bin/bash for ((i=1;i<=10;i++)) do ping -c 3 -i 0.2 -W 3 "192.168.100.$i" &> /dev/null if [ $? -eq 0 ] then echo "Host 192.168.100.$i is up" else echo "Host 192.168.100.$i is down" fi done ~ [root@shanan test]# vi ping.sh [root@shanan test]# sh ping.sh Host 192.168.100.1 is up Host 192.168.100.2 is up Host 192.168.100.3 is down Host 192.168.100.4 is down Host 192.168.100.5 is down Host 192.168.100.6 is down Host 192.168.100.7 is down Host 192.168.100.8 is down Host 192.168.100.9 is down Host 192.168.100.10 is down
方式一:
#!/bin/bash for ((i=1;i<=10;i++)) do echo "$i" done 方式二: #!/bin/bash i=1 for ((;i<=10;i++)) do echo "$i" done 方式三: #!/bin/bash i=1 for ((;i<=10;)) do echo "$i" let i++ done 方式四: #!/bin/bash i=1 for ((;;)) do if [ $i -le 10 ] then echo "$i" let i++ else exit 0 fi done 输出结果 [root@shanan test]# sh shi.sh 1 2 3 4 5 6 7 8 9 10
let 对整数进行数学运算
let和双小括号 (( )) 一样,let 命令也只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。
语法格式
let 表达式
或
let "表达式"
或
let '表达式'
以上方式都等价于 ((表达式))
当表达式中含有 Shell 特殊字符(例如 |)时,需要用双引号" "或者单引号’ '将表达式包围起来。
和 (( )) 类似,let 命令也支持一次性计算多个表达式,并且以最后一个表达式的值作为整个 let 命令的执行结果。
方式一:计算偶数的和
#!/bin/bash
sum=0
for((i=0;i<=10;i+=2))
do
let sum+=$i
done
echo "总和为:$sum"
方式一:计算奇数的和
#!/bin/bash
sum=0
for((i=1;i<=10;i+=2))
do
let sum+=$i
done
echo "总和为:$sum"
方式二:求偶数和
#!/bin/bash
sum=0
for((i=0;i<=10;i+=2))
do
if [ `expr $i % 2` -eq 0 ]
then
let sum+=$i
fi
done
echo "总和为:$sum"
方式二:求奇数和
#!/bin/bash
sum=0
for((i=1;i<=10;i+=2))
do
if [ `expr $i % 2` -eq 1 ]
then
let sum+=$i
fi
done
echo "总和为:$sum"
重复测试某个条件,只要条件成立则反复执行
语句结构
while 条件测试操作
do
命令序列
done
语句结构示例
while 未猜中正确的价格
do
反复猜测商品价格
done
### 1.2.2:while语句应用示例 使用while循环语句输出1-10数字 #!/bin/bash i=0 while [ $i -le 10 ] do echo "$i" let i++ done 运行结果 0 1 2 3 4 5 6 7 8 9 10
while true:死循环有时候也有奇效,可与用户交互
#!/bin/bash while true do read -p "请输入yes退出:" KEY if [ $KEY = yes ] then break fi done echo "正常退出" 运行结果: 请输入yes退出:no 请输入yes退出:1 请输入yes退出:d 请输入yes退出:! 请输入yes退出:a 请输入yes退出:yes 正常退出
用户名称以stu开头,按数字顺序进行编号
一共添加20个用户,即stu1,stu2…stu20
初始密码设置为123456
#!/bin/bash i=0 while [ $i -le 19 ] do let i++ useradd stu$i echo "123456" | passwd --stdin stu$i &> /dev/null echo "stu$i添加成功" done echo "添加完毕" 运行结果 .......省略 stu15添加成功 stu16添加成功 stu17添加成功 stu18添加成功 stu19添加成功 stu20添加成功 添加完毕
通过变量RANDOM获得随机数
提示用户猜测并记录次数,猜中后退出循环
#!/bin/bash A=`expr $RANDOM % 1000` i=0 echo "商品的实际价格为0-999之间,猜猜看是多少?" read -p "请输入你猜测的价格数目:" num while [ $num -le 999 ] && [ $num -ge 1 ] do let i++ if [ $num -eq $A ] then echo "恭喜你答对了,实际价格是$A" echo "你一共猜测了$i 次" exit 0 elif [ $num -lt $A ] then echo "太低了" read -p "请输入你猜测的价格数目:" num else echo "太高了" read -p "请输入你猜测的价格数目:" num fi done [root@ shanan ~]# sh jiage.sh 商品的实际价格为0-999之间,猜猜看是多少? 请输入你猜测的价格数目:500 太高了 请输入你猜测的价格数目:250 太高了 请输入你猜测的价格数目:125 太低了 请输入你猜测的价格数目:200 太高了 请输入你猜测的价格数目:160 太高了 请输入你猜测的价格数目:140 太高了 请输入你猜测的价格数目:130 太低了 请输入你猜测的价格数目:135 太低了 请输入你猜测的价格数目:137 太低了 请输入你猜测的价格数目:138 恭喜你答对了,实际价格是138 你一共猜测了10 次
命令格式
continue n
n 表示循环的层数:
如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环同时执行了不带 n 的 continue。这么说可能有点难以理解,稍后我们通过代码来演示。
continue 关键字也通常和 if 语句一起使用,即满足条件时便跳出循环。
命令格式
break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。
break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。
break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。
#!/bin/bash i=1 while [ $i -le 9 ] do for ((j=1;j<=$i;j++)) do echo -en "\t $j x $i = `expr $j \* $i`" done let i++ echo " " done ~ [root@shanan ~]# sh cfb.sh 1 x 1 = 1 1 x 2 = 2 2 x 2 = 4 1 x 3 = 3 2 x 3 = 6 3 x 3 = 9 1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25 1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36 1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49 1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8 = 56 8 x 8 = 64 1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
奖池观众:
奖池观众名单在name.txt中 GONE:H:P 共10次投票,使用随机数的方法挑选幸运观众,票数最多获胜 #!/bin/bash B=0 C=0 D=0 for ((i=1;i<=10;i++)) do #A=$( expr $[RANDOM%3+1]) A=$[$RANDOM%3+1] list=$(cut -d ':' -f$A /test/name.txt ) case $list in GONE) let B++ ;; [H]) let C++ ;; *) let D++ esac done echo " GONE的票数是 $B" echo " H 的票数是 $C" echo " P 的票数是 $D" [root@ shanan ~]# sh luck.sh GONE的票数是 4 H 的票数是 5 P 的票数是 1
重复测试某个条件,只要条件不成立则反复执行
until 条件测试操作
do
命令序列
done
while 未超过10
do
数字依次增加
done
计算1–50的和
通过循环累加的方式计算1–50的和
#!/bin/bash
i=1
S=0
until [ $i -eq 51 ]
do
let S+=$i
let i++
done
echo "$S"
运算结果
1275
为指定用户发送在线消息
若指定用户不在线(未登陆系统),则每10分钟(实验中为了测试效果,可改为3s)试一次,直至用户登录系统后再发送信息
用户名与消息通过为止参数传递给脚本
[root@ shanan test]# vi yonghu.sh #!/bin/bash username=$1 #判断格式参数是否为空 if [ $# -lt 1 ] then echo "Usage:`basename $0` <username> [<message>]" exit 1 fi #判断账号是属于系统用户 if grep "^$username:" /etc/passwd &> /dev/null;then : else echo "用户不存在" exit 2 fi #判断用户是否在线,若不在线每3秒联系一次 until who | grep "$username" &> /dev/null do echo "用户不在线,正在尝试连接" sleep 3 done #发送消息 echo "$2" | write "$username" echo "${username}发送成功" 运行脚本: [root@ shanan test]# sh yonghu.sh Usage:yonghu.sh <username> [<message>] [root@ shanan test]# yonghu.sh lucy -bash: yonghu.sh: 未找到命令 [root@ shanan test]# sh yonghu.sh lucy hello lucy发送成功 [root@ shanan test]# sh yonghu.sh stu20 hello 用户不在线,正在尝试连接 用户不在线,正在尝试连接 用户不在线,正在尝试连接
[lucy@ shanan ~]$
Message from root@ shanan on pts/1 at 19:07 ...
hello
EOF
shell一个非常重要的特性是它可作为一种编程语言来使用。
因为shell是一个解释器,所以它不能对为它编写的程序进行编译,而是在每次从磁盘加载这些程序时对它们进行解释。而程序的加载和解释都是非常耗时的。
针对此问题,许多shell(如BourneAgainShell)都包含shell函数,shell把这些函数放在内存中,这样每次需要执行它们时就不必再从磁盘读入。
shell还以一种内部格式来存放这些函数,这样就不必耗费大量的时间来解释它们
shell函数将命令序列按格式写在一起
可以方便重复使用命令序列
其中,return返回的是状态码,需要使用$?调取
echo 返回的是值,使用变量调用
传参:指位置变量
可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255
函数名 [参数1($1)] [参数2($2)]
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,
2
表
示
第
二
个
参
数
…
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
不
能
获
取
第
十
个
参
数
,
获
取
第
十
个
参
数
需
要
10
。
当
n
>
=
10
时
,
需
要
使
用
2表示第二个参数… 10不能获取第十个参数,获取第十个参数需要 10 不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用
2表示第二个参数…10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要10不能获取第十个参数,获取第十个参数需要10。当n>=10时,需要使用{n}来获取参数。
两个数字求个
通过sum(){}定义函数
使用read命令交互输入两个数并求和
#!/bin/bash #sum=0 function A (){ read -p "请输入第一个数字:" B read -p "请输入第二个数字:" C sum=`expr $B + $C` echo "$B + $C = $sum" return 3 } #echo $sum A $B $C 运行结果 请输入第一个数字:4 请输入第二个数字:2 4 + 2 = 6
编写登录系统后便可使用的自定义函数
编辑用户自定义函数文件/root/function
在当前shell中加载可执行的函数文件/root/function
在~/.bashrc文件中添加source /root/function命令
#!/bin/bash function list_file(){ for f in ` ls $1 ` do #判断是不是目录 if [ -d "$1/$f" ];then echo "$2$f" #递归调用 list_file "$1/$f" " $2" else echo "$2$f " fi done } list_file "/var/log" "" 运行结果 [root@ shanan test]# sh digui.sh anaconda anaconda.log ifcfg.log journal.log ks-script-Sp6XrL.log packaging.log program.log storage.log syslog X.log audit audit.log boot.log boot.log-20200713 boot.log-20200714 boot.log-20200715 boot.log-20200716 boot.log-20200717 boot.log-20200718 boot.log-20200723 ........省略若干
函数在Shell脚本中仅在当前Shell环境中有效
Shell脚本中变量默认全局有效
将变量限定在函数内部使用local命令
示例
函数内部变量通过local来实现
通过定义score函数,在期内部设置局部变量i
函数内部和外部分别赋值,进行结果验证
#!/bin/bash
#求和函数体
function sum(){
#命令序列
read -p "请输入第一个整数:" num1
read -p "请输入第二个整数:" num2
SUM=$(($num1+$num2))
#echo 返回的是处理结果值
local score=100
echo "函数内$score"
echo "和:$SUM"
}
sum
echo "函数外$score"
获取数组长度
使用for循环获取具体信息,使用下标或索引标记数组中数据的位置
可以存放多种数据,如:整型,长整形,浮点型(单精度,双精度),字符串等
获取元素长度
遍历元素
元素切片
元素替换
元素删除
…
注意,忌讳数组越界,
数组下标从0开始算
数组长度从1开始算
长度为4,数组长度表示为1,2,3,4;数组下标表示为0,1,2,3
shell中数组是可变长的
方法一: 基本格式 数组名=(value0 value1 value2...) 1 2 例如 ABC=(11 22 33...) 1 2 方法二: 基本格式 数组名=([0]=value [1]=value [2]=value...) 1 2 例如 ABC=([0]=11 [1]=22 [2]=33...) 1 2 方法三:数组元素之间使用空格隔开 基本格式 列表名=“value0 value1 value2” 数组名=($列表名) 1 2 3 例如 AAA=“11 22 33...” ABC=($列表名) 1 2 3 方法四: 基本格式 数组名[0]=“value” 数组名[1]=“value” 数组名[2]=“value” ... 例如 AAA[0]=“11” AAA[1]=“22” AAA[2]=“33” ...
数值类型
字符类型
使用“”或‘’定义
数组只可存放数值或字符
获取数组长度
基本格式 ${#数组名[@/*]} 例如 [root@localhost opt]# abc=(10 20 30) [root@localhost opt]# echo ${abc[*]} 10 20 30 [root@localhost opt]# echo ${#abc[*]} 读取某下标赋值 基本格式 ${数组名[下标]} 例如 [root@localhost opt]# echo ${abc[1]} 20 [root@localhost opt]# echo ${abc[0]} 10 [root@localhost opt]# echo ${abc[1]} 20 [root@localhost opt]# echo ${abc[2]} 30 ## 3.4:求数组最大值 #!/bin/bash score=(34 88 99 54 76) temp=0 for ((i=0;i<${#score[*]};i++));do #比较大小,大的赋予给temp if [ ${score[$i]} -gt $temp ];then temp=${score[$i]} fi done echo $temp 运行结果 [root@ shanan ~]# sh big.sh 99
[root@ shanan ~]# vi chuangjian.sh #!/bin/bash #创建任意数字及长度的数组,根据客户需求加入元素 i=0 #数组下标 while true #保持为真,死循环 do read -p "是否加入元素 (yes/no): " doing if [ $doing == "no" ]; then break fi read -p "请存入第$[$i+1]个元素: " key arr[$i]=$key let i++ done echo ${arr[*]} 运行结果 [root@ shanan ~]# sh chuangjian.sh 是否加入元素 (yes/no): yes 请存入第1个元素: 1 是否加入元素 (yes/no): yes 请存入第2个元素: 2 是否加入元素 (yes/no): yes 请存入第3个元素: 3 是否加入元素 (yes/no): yes 请存入第4个元素: 4 是否加入元素 (yes/no): yes 请存入第5个元素: 5 是否加入元素 (yes/no): no 1 2 3 4 5
[root@ shanan ~]# vi c100.sh #!/bin/bash #创建存放(1-100)奇数的数组 k=0 j=1 for ((i=0;i<=99;i++));do k=$[$i+$j] let j++ #最大元素不能超过100 if [ $k -le 100 ];then arr[$i]=$k fi done echo ${arr[*]} 运行结果: [root@ shanan ~]# sh c100.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
[root@ shanan ~]# vi s60.sh #!/bin/bash #原始数组 score=( 50 98 56 87 43 ) #遍历数组 for ((i=0;i<${#score[*]};i++ ));do #判断是否大于60,未满足60直接赋予60 if [ ${score[$i]} -lt 60 ];then new[$i]=60 else new[$i]=${score[$i]} fi done echo ${new[*]} ~ 运行结果: [root@ shanan ~]# sh s60.sh 60 98 60 87 60 从小到大,冒泡排序 [root@ shanan ~]# vi paixu.sh #!/bin/bash score=(72 63 88 91 45) #外层一轮 for ((i=1;i<${#score[*]};i++));do #内层一次 for ((j=0;j<${#score[*]}-i;j++));do #两数交换 if [ ${score[$j]} -gt ${score[`expr $j + 1`]} ];then tmp=${score[`expr $j + 1`]} score[`expr $j + 1`]=${score[$j]} score[$j]=$tmp fi done done echo ${score[*]} 运行结果: [root@ shanan ~]# sh paixu.sh 45 63 72 88 91
#!/bin/bash #创建任意数字及长度的数组,根据客户需求加入元素 i=0 #数组下标 while true #保持为真,死循环 do read -p "是否加入元素 (yes/no): " doing if [ $doing == "no" ]; then break fi read -p "请存入第$[$i+1]个元素: " key score[$i]=$key let i++ done for ((i=1;i<${#score[*]};i++));do #内层一次 for ((j=0;j<${#score[*]}-i;j++));do #两数交换 if [ ${score[$j]} -gt ${score[`expr $j + 1`]} ];then tmp=${score[`expr $j + 1`]} score[`expr $j + 1`]=${score[$j]} score[$j]=$tmp fi done done echo ${score[*]} 运行结果: [root@ shanan ~]# vi chuangjian.sh [root@ shanan ~]# sh chuangjian.sh 是否加入元素 (yes/no): yes 请存入第1个元素: 4 是否加入元素 (yes/no): yes 请存入第2个元素: 6 是否加入元素 (yes/no): yes 请存入第3个元素: 8 是否加入元素 (yes/no): yes 请存入第4个元素: 2 是否加入元素 (yes/no): no 2 4 6 8
[root@ shanan ~]# vi shanchu.sh
#!/bin/bash
arr=(67 44 88 52 93 55 59)
i=0
for v in ${arr[*]};do
if [ $v -lt 60 ]; then
unset arr[$i]
fi
let i++
#echo ${#arr[*]}
done
echo ${arr[*]}
运行结果
[root@ shanan ~]# sh shanchu.sh
67 88 93
[root@ shanan ~]# vi daxiao.sh #!/bin/bash num=(10 60 100 90 80 70 65 59 89 56) #temp=0 for ((i=0;i<${#num[*]};i++)) do for ((j=$i+1;j<${#num[*]};j++)) do if [ ${num[$i]} -gt ${num[$j]} ];then temp=${num[$i]} let num[$i]=${num[$j]} let num[$j]=temp #else #temp=${num[$i]} fi done done echo ${num[*]} 运行结果》: [root@ shanan ~]# sh daxiao.sh 10 56 59 60 65 70 80 89 90 100
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。