C高级——shell(3)
一、shell的选择结构
1.回顾:C语言的选择结构:if , if else if ,if else,switch (switch的执行速度最快)
2.shell的选择结构: 单分支if 双分支 if else 多分支if elif case..in
1.1 shell的选择结构的格式
--------C语言的格式------
单分支
if(表达式)
{
C语句
}
双分支
if(表达式)
{
C语句1
}
else
{
C语句2
}
多分支
if(表达式1)
{
C语句1
}
else if(表达式2)
{
C语句2;
}
....
else
{
C语句n;
}
-------------------shell的格式------
单分支
if 表达式
then
SHELL语句
fi
执行流程:如果表达式为真,则执行shell语句,否则退出
双分支
if 表达式
then
shell语句1
else
shell语句2
fi
执行流程:如果表达式为真,则执行shell语句1,否则执行shell语句2
多分支
if 表达式1
then
shell语句1
elif 表达式2
then
shell语句2
....
else
shell语句n
fi
执行流程:如果表达式1为真,则执行shell语句1,结束
如果表达式1为假,则继续判断表达式2,如果表达式2为真,则执行shell语句2,结束
重复以上过程
1.2 shell选择结构练习
1.输入一个数,判断奇数偶数
2.输入一个数,判断是否是水仙花
水仙花:各个位数字立方和等于本身,是三位数
eg: 153==1*1*1+5*5*5+3*3*3
if ((a%2==0))
then
偶数
else
奇数
fi
if ((a%2==0))
then
偶数
fi
if ((a%2!=0))
then
奇数
fi
if ((a%2==0))
then
偶数
elif ((a%2!=0))
then
奇数
fi
#!/bin/bash
read -p "please enter a:" a
if ((a%2==0))
then
echo 偶数
else
echo 奇数
fi
read -p "please enter num:" num
if (($num>100&&num<999))
then
g=$((num%10))
s=$((num/10%10))
b=$((num/100))
if ((g**3+s**3+b**3==num))
then
echo 是水仙花
else
echo 不是水仙换
fi
else
echo 不是三位数
fi
1.3 test指令和if结合
1.test是一个指令:必须添加空格,必须写$,必要时写双引号 man test
2.test实现的操作:逻辑运算,关系运算,字符串,文件
3.test指令等价于[]
1.3.1 test和if结合的格式
格式1:
if test 表达式
then
shell语句
fi
格式2:
if [ 表达式 ] 注意[]的左右必须添加空格
then
shell语句
fi
1.3.2 test的指令
【1】逻辑运算
格式1:if [ 表达式1 -a 表达式2 ]
格式2:if [ 表达式1 ] && [ 表达式2 ]
格式3:if [ 表达式1 -o 表达式2 ]
格式4:if [ 表达式1 ] || [ 表达式2 ]
1.判断表达式为真
( EXPRESSION )
EXPRESSION is true
判断a不为0
if(a!=0) --->if(a) --->if [ $a ]
2.判断表达式为假
! EXPRESSION
EXPRESSION is false
判断a等于
if(a==0) ---->if(!a) ---->if [ ! $a ]
3.逻辑与运算,遇假则假,全真为真
EXPRESSION1 -a EXPRESSION2
both EXPRESSION1 and EXPRESSION2 are true
判断a>b>c
if(a>b&&b>c) ---->if [ $a -gt $b -a $b -gt $c ]
--->if [ $a -gt $b ] && [ $b -gt $c ]
4.逻辑或运算,遇真则真,全假为假
EXPRESSION1 -o EXPRESSION2
either EXPRESSION1 or EXPRESSION2 is true
判断成绩不合格<0 >100
if(a<0 || a>100) --->if [ $a -lt 0 -o $a -gt 100 ]
--->if [ $a -lt 0 ] || [ $a -gt 100 ]
练习:输入一个年份,判断润年
润年:能被4整除,但不可以被100整除,或者可以被400整除
read -p "please enter year:" year
if [ $((year%4)) -eq 0 -a $((year%100)) -ne 0 -o $((year%400)) -eq 0 ]
then
echo 是润年
else
echo 不是润年
fi
判断偶数 ---》if [ a%4==0 ] --->if [ $((a%4)) -eq 0 ]
【2】关系运算
1.判断两个整数是否相等
INTEGER1 -eq INTEGER2
INTEGER1 is equal to INTEGER2
判断a和b相等
if test $a -eq $b ----> if [ $a -eq $b ]
2.判断整数1大于等于整数2
INTEGER1 -ge INTEGER2
INTEGER1 is greater than or equal to INTEGER2
判断a大于等于b
if test $a -ge $b ----> if [ $a -ge $b ]
3.判断整数1大于整数2
INTEGER1 -gt INTEGER2
INTEGER1 is greater than INTEGER2
4.判断整数1小于等于整数2
INTEGER1 -le INTEGER2
INTEGER1 is less than or equal to INTEGER2
5.判断整数1小于整数2
INTEGER1 -lt INTEGER2
INTEGER1 is less than INTEGER2
6.判断两个整数不相等
INTEGER1 -ne INTEGER2
INTEGER1 is not equal to INTEGER2
练习:输入三个数,实现升序排序
a b c 要求:a存储最小值 b存储中间值 c存储最大值
#!/bin/bash
read -p "please enter arr" -a arr
#1.判断arr[0] arr[1]
if [ ${arr[0]} -gt ${arr[1]} ]
then
t=${arr[0]}
arr[0]=${arr[1]}
arr[1]=$t
fi
#判断arr[1] arr[2]
if [ ${arr[1]} -gt ${arr[2]} ]
then
t=${arr[1]}
arr[1]=${arr[2]}
arr[2]=$t
fi
#判断arr[0] arr[1]
if [ ${arr[0]} -gt ${arr[1]} ]
then
t=${arr[0]}
arr[0]=${arr[1]}
arr[1]=$t
fi
echo ${arr[*]}
【3】字符串
1.判断字符串长度不为0
-n STRING
the length of STRING is nonzero
STRING equivalent to -n STRING
判断str不为空
if [ -n "$str" ]
2.判断字符串长度为0
-z STRING
the length of STRING is zero
判断str为空
if [ -z "$str" ]
3.判断两个字符串是否相等
STRING1 = STRING2
the strings are equal
判断字符串ab是否相等
if [ $a = $b ]
4.判断两个字符串不相等
STRING1 != STRING2
the strings are not equal
判断字符串ab不相等
if [ $a != $b ]
5.判断字符串的大小关系
if [ $a > $b ]
if [ $a < $b ]
练习:输入两个字符串,如果有一个为空则提示空,否则判断= > <
read a
read b
if [ -z "$a" -o -z "$b" ]
then
echo NULL
else
if [ $a "=" $b ]
then
echo "="
elif [ $a ">" $b ]
then
echo ">"
elif [ $a "<" $b ]
then
echo "<"
fi
fi
【4】文件
文件类型:bcd-lsp
参数: bcdfLSp
1.判断两个文件谁跟新(修改的时间)
FILE1 -nt FILE2
FILE1 is newer (modification date) than FILE2
两个文件file1 file2
if [ $file1 -nt $file2 ]
2.判断文件谁跟旧
FILE1 -ot FILE2
FILE1 is older than FILE2
两个文件file1 file2
if [ $file1 -ot $file2 ]
3. 判断是否是块设备文件以及存在
-b FILE
FILE exists and is block special
文件file是否是块设备文件
if [ -b $file ]
4. 判断文件存在且是一个字符设备文件
-c FILE
FILE exists and is character special
if [ -c $file ]
5.判断文件存在且是一个目录
-d FILE
FILE exists and is a directory
6.判断文件是否存在
-e FILE
FILE exists
7.判断文件存在且是一个普通文件
-f FILE
FILE exists and is a regular file
8.判断文件存在且是一个链接文件
-h FILE
FILE exists and is a symbolic link (same as -L)
-L FILE
FILE exists and is a symbolic link (same as -h)
9.判断文件存在且是一个管道文件
-p FILE
FILE exists and is a named pipe
10.判断文件存在且文件大小大于0,文件不为空
-s FILE
FILE exists and has a size greater than zero
11.判断文件存在且是一个套接字文件
-S FILE
FILE exists and is a socket
12.判断文件存在且具备可读权限
-r FILE
FILE exists and read permission is granted
13.判断文件存在且具备写权限
-w FILE
FILE exists and write permission is granted
14.判断文件存在且具备可执行权限
-x FILE
FILE exists and execute (or search) permission is granted
练习:终端输入文件名,输出文件对应的类型以及对应的权限
1.4 case ..in
---------------C语言switch----
switch(表达式)
{
case 常量表达式1:C语句; break;
case 常量表达式2:C语句; break;
case 常量表达式3:C语句; break;
...
default:C语句n;break;
}
----------------case..in--------
格式:
case varName in
常量表达式1)
shell语句
;;
常量表达式2)
shell语句
;; ------》不可以省略
....
*)
shell语句
;; ----》可以省略不写
esac
解析:
1.varName:只是一个变量 类似switch中的表达式
2.常量表达式:
2.1常见格式:
hello)
'hello')
"hello")
2.2可以和按位或链接
A|a) --->A或a则执行
Y|y|yes|YES)
2.3可以和通配符结合使用
h*)
?
[]
70-89B
[7-8][0-9])
3.;; --->类似C语言break,退出case..in, 可有可无
4.*) 类似default 执行除上面案例的所有情况
练习:输入一个表达式,输出对应的值 +-*%
1+2 ---》3
a=1
b=+
c=2
switch(b)
{
case '+':printf("%d",a+b);break;
case '-':printf("%d",a+b);break;
case '*':printf("%d",a+b);break;
case '/':printf("%d",a+b);break;
case '%':printf("%d",a+b);break;
default:error;break;
}
read a b c
case $b in
+)
echo $a$b$c=$((a+c))
;;
-)
echo $a$b$c=$((a-c))
;;
"*")
echo $a$b$c=$((a*c))
;;
/)
echo $a$b$c=$((a/c))
;;
%)
echo $a$b$c=$((a%c))
;;
*)
echo input error
;;
esac
二、shell循环结构
1.回顾C语言的循环:while\ for\ do..while
2.shell的循环: while\for\select..in
2.1 while
------------------C语言----
while(表达式)
{
C语句
}
------------------shell循环格式----
格式
#while test 表达式
while [ 表达式 ] --->while [ 1 ] 死循环
do
shell语句
done
执行流程:如果表达式为真则进入循环,表达式为假则退出循环
练习:循环1--5
i=1
while [ $i -le 5 ]
do
echo i=$i
((i++))
done
练习:输入一个数组,使用while循环输出数组元素,计算数组元素的和
read -p "please enter arr:" -a arr
i=0
while [ $i -lt ${#arr[*]} ]
do
echo arr[$i]=${arr[$i]}
((sum+=arr[i]))
((i++))
done
echo sum=$sum
11.2 for
while:属于当型循环,先判断后执行,最少执行0次,属于有条件控制(不清楚循环次数)
for: 属于当型循环,先判断后执行,最少执行0次,属于计数控制(循环次数明确)
do..while:属于直到型循环,先执行后判断,最少执行1次,属于条件控制(循环次数不明确)
---------------------C语言for循环格式----
for(表达式1;表达式2;表达式3)
{
C语句
}
表达式1:起始值
表达式2:循环条件
表达式3:步长
-------------------shell的格式--------
格式1:类似于C语言的格式
for ((表达式1;表达式2;表达式3))
do
shell语句
done
执行流程:先表达式1,执行表达式2,如果表达式2为真则继续循环,后执行表达式3,如果表达式2为假
则结束循环
格式2:可以实现稀疏数组的循环
for varName in 选项列表
do
shell语句
done
格式3:
for varName -----》
do
shell语句
done
注意:"in 选项列表"如果不写,则默认varName的结果是终端输入的字符串也就是命令置换$1 $2 $3...
解析:
1.varName: 循环变量,类似i
2.选项列表:每个元素之间使用空格隔开
2.1 选项列表为固定的字符换
for i in 1 2 3 4
do
echo $i
done
2.2 选项列表的值为数组
arr=(11 22 33)
for i in ${arr[*]}
do
echo $i
done
2.3 选项列表可以使用seq指令
格式:seq 起始值 间隔 终止值
eg: seq 1 2 10 ----->1 3 5 7 9
使用: `seq 起始值 间隔 终止值` $(seq 起始值 间隔 终止值)
for i in `seq 2 2 8`
a=2 b=8
for i in `seq $a 2 $b`
2.4 选项列表可以使用{1..3},起始值和终止值必须是常量
{1..3} --->1 2 3
3.执行流程:依次把选项列表的每个元素赋值给变量varName,如果选项列表的元素赋值结束,则结束循环
练习:输入一个数组,计算最大值,使用for实现
练习: 打印图片
*
**
***
****
for((i=1;i<=4;i++))
do
for((j=1;j<=i;j++))
do
echo -n "*" #取消换行打印
done
echo #换行
done
read -p "please enter arr:" -a arr
max=${arr[0]}
for var in ${arr[*]}
do
if [ $max -lt $var ]
then
max=$var
fi
done
echo max=$max
2.3 select..in
select..in: 增强和终端页面的交互性
格式:
select varName in 选项列表
do
shell语句
done
解析:
1.varName和选项列表: 与for循环一样
2.select..in执行流程:在#?的后面输入指定序列,如果序列号存在,则把指定对应的元素赋值给varName
如果#?不输入世界回车,则重新打印页面,如果在#?的后面输入的值不在列表中,则重新输入
ctrl c\ ctrl d结束循环
eg:
select var in 11 22 33 44
do
echo var=$var
done
2.4 select..in和case..in结合使用
练习:使用select..in和case..in实现计算器
1)+
2)-
3)*
4)/
5)%
#?
read a c #1 2
select b in + - "*" / %
do
case $b in
+)
echo $a$b$c=$((a+c))
;;
-)
echo $a$b$c=$((a-c))
;;
"*")
echo $a$b$c=$((a*c))
;;
/)
echo $a$b$c=$((a/c))
;;
%)
echo $a$b$c=$((a%c))
;;
*)
echo input error
;;
esac
done
三、练习:
3.1 使用case..in实现等级判断,输入一个成绩,判断等级
#!/bin/bash
read grade
case $grade in
9[0-9]|100)
echo A
;;
8[0-9])
echo B
;;
7[0-9])
echo C
;;
6[0-9])
echo D
;;
[1-5][0-9]|[0-9])
echo 不及格
;;
*)
echo error
;;
esac
3.2任意输入一个数,使用while循环计算各个位数字之和
#!/bin/bash
read -p "请输入一个数:" num
sum=0
n=$num
while [ $num -gt 0 ]
do
sum=$((num%10+$sum))
num=$((num/10))
done
echo $n各个位数和为$sum
3.3 输入一个字符串,使用while循环实现字符串逆置
#!/bin/bash
read str
len=${#str}
echo str=$str
for i in `seq 1 1 $len`
do
NewStr=$NewStr${str:0-i:1}
done
echo 逆置后:str=$NewStr
3.4循环家目录下的所有内容,计算家目录下 目录的个数,普通文件的个数,使用for循环
#!/bin/bash
arr=(`ls ~`)
len=${#arr[*]}
qt=0
for i in `seq 0 1 $(($len-1))`
do
if [ -d ~/${arr[$i]} ]
then
((qt++))
fi
done
echo 家目录下目录数量为$qt
qt=0
for i in `seq 0 1 $(($len-1))`
do
if [ -f ~/${arr[$i]} ]
then
((qt++))
fi
done
echo 家目录下普通文件数量为$qt
3.5 打印图形
*
***
*****
*******
#!/bin/bash
for i in {1..4}
do
for ((j=4-i;j>0;j--))
do
echo -n " "
done
for ((k=2*i-1;k>0;k--))
do
echo -n "*"
done
echo
done
3.6 输入一个数组,请实现冒泡排序
#!/bin/bash
read -p "请输入数组元素:" -a arr
len=${#arr[*]}
for i in `seq 1 1 $len`
do
for j in `seq 0 1 $(($len-$i-1))`
do
if [ ${arr[$j]} -gt ${arr[$((j+1))]} ]
then
temp=${arr[$j]}
arr[j]=${arr[$((j+1))]}
arr[$((j+1))]=$temp
fi
done
done
echo ${arr[*]}
3.7 输入一个数组,请实现插入排序
#!/bin/bash
read -a arr -p "请输入数组中的元素:"
len=${#arr[*]}
sun=0
for i in `seq 1 1 $(($len-1))`
do
temp=${arr[$i]}
for ((j=i-1;j>=0;j--))
do
if [ $temp -le ${arr[$j]} ]
then
arr[$((j+1))]=${arr[$j]}
else
arr[$((j+1))]=$temp
j=-1
fi
done
done
echo ${arr[*]}
3.8 输入用户名和密码(加密输入),实现密码的三次登录 默认用户名admin 密码1234 账户存款10000
如果登录失败,则提示
第1次登录失败,还有2次机会
第2次登录失败,还有1次机会
第3次登录失败,账户被锁定
如果登录成功,则显示银行页面
1.账户余额
2.取款
3.存款
如果选择1,则打印当前的余额
如果选择2,则输入取款金额,如果取款金额大于实际金额,则提示账户余额不足,请重新输入,如果账户余额小于等于实际金额,则提示取款成功,打印剩余金额
如果选择3,则输入存款金额,并提示 存款成功,余额的值
#!/bin/bash
count=1
balance=10000
while [ $count -le 3 ]
do
read -p "请输入用户名:" name
read -p "请输入密码:" -s passwd
if [ $name=="admin" -a $passwd=="1234" ]
then
echo
select choice in 账户余额 取款 存款
do
case $choice in
账户余额)
echo 账户余额:$balance
;;
取款)
read -p "请输入取款金额:" mount
if [ $mount -gt $balance ]
then
echo 余额不足,请重新输入
else
balance=$((balance-mount))
echo 取款成功
echo 账户余额:$balance
fi
;;
存款)
read -p "请输入存款金额:" mount
balance=$((balance+mount))
echo 存款成功
echo 账户余额:$balance
;;
*)
echo error
;;
esac
done
elif [ $name!="admin" || $passwd!="1234" ]
then
if [ $count -eq 3 ]
then
echo 第$count次登录失败,账户被锁定
else
echo "第$count次登录失败,还有$((3-$count))次机会"
fi
((count++))
fi
done