流程控制
顺序执行
If
单分支
if 判断条件;then 条件为真的分支代码fi
双分支
if 判断条件;then 条件为真的分支代码 else 条件为假的分支代码 fi
多分支
if 判断条件1; then 条件为真的分支代码 elif判断条件2; then 条件为真的分支代码 elif判断条件3; then 条件为真的分支代码 else 以上条件都为假的分支代码 fi
elif下同样可接else。表示第一个条件为真,第二条件为假的情况
根据命令的退出状态来执行命令
if echo $name|grep "$n" &> /dev/null ;then
选择执行
Case
case 变量引用in PAT1)分支1;; PAT2)分支2;; #注意分支结束一定要能够用;; ... *)默认分支;; esac
case支持glob风格的通配符:
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b
循环执行
将某代码段重复运行多次
重复运行多少次:
循环次数事先已知
循环次数事先未知
有进入条件和退出条件
For
for 变量名in 列表;do 循环体 done
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
例:利用for打印九九乘法表
#!/bin/bash
for a in {1..9} ;do
b=$a
for b in $(seq $b 9);do
echo -n "$a*$b=$[$a*$b] "
done
echo
done
结果为
[[email protected] shell0]# ./99f.sh
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*6=36 6*7=42 6*8=48 6*9=54
7*7=49 7*8=56 7*9=63
8*8=64 8*9=72
9*9=81
While
while CONDITION; do 循环体 done
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false
例:利用while打印九九乘法表
#!/bin/bash
i=1
while [ $i -lt 10 ];do
b=$i
while [ $b -lt 10 ];do
echo -n "$i*$b=$[$i*$b] "
b=$[$b+1]
done
i=$[$i+1]
echo
done
输出结果
[[email protected] shell0]# ./99w.sh
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*6=36 6*7=42 6*8=48 6*9=54
7*7=49 7*8=56 7*9=63
8*8=64 8*9=72
9*9=81
例:编写脚本/root/bin/copycmd.sh
(1) 提示用户输入一个可执行命令名称
(2) 获取此命令所依赖到的所有库文件列表
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;如:/bin/bash ==> /mnt/sysroot/bin/bash /usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出
#!/bin/bash echo "停止请输入quit" while true;do #永真循环 read -p 请输入一个命令: cmd if [[ $cmd =~ quit ]];then #输入exit退出 exit fi a=$(which $cmd| tail -1) #查询命令来自哪个文件 mkdir -p /app/sysroot$(echo $a|egrep -o "/.*/") &> /dev/null cp -v $a /app/sysroot/$a #复制命令 b=$(ldd /usr/bin/ls|cut ‘-d ‘ -f3) #查询命令需要哪些库文件,这里有一个库文件是集成在内核里的不需要拷贝 for n in $b;do if [ $n != ‘ ‘ ];then mkdir -p /app/sysroot$(echo $n|egrep -o "/.*/") &> /dev/null cp -v $n /app/sysroot$n #复制库文件 fi done done
Until
与while完全一样只是判断条件不同
until CONDITION; do 循环体 done
进入条件:CONDITION 为false
退出条件:CONDITION 为true
Select
select variable in list do case 变量引用in PAT1)分支1;; PAT2)分支2;; #select 经常与case一起使用 ... *)默认分支;; esacdone
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误
上,并显示PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY 中
循环控制语句
Continue
用于循环体中
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层(不写默认为1)
Break
用于循环体中
break [N]:提前结束第N层循环,最内层为第1层
Shift
shift [n]
用于将参量列表list 左移指定次数,缺省为左移一次。
参量列表list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到shift
函数
语法一:
function f_name{
...函数体...
}
语法二:
function f_name(){
...函数体...
}
语法三:
f_name(){
...
}
数组
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
索引:编号从0开始,属于数值索引
注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持
bash的数组支持稀疏格式(索引不连续)
声明数组:
declare -a ARRAY_NAME
declare -A ARRAY_NAME: 关联数组
注意:两者不可相
例:1
为某餐馆用Shell制作一个点菜系统。功能如下:执行脚本会列出主菜单,如下
请选择您要吃的菜品
(消费满80打8折)
1)饭 2)面、
3)饺子 4)结账
等待用户选择
如选择1,则再问 如选择2,则再问 如选择3,则再问 如选择4,则直接退出
1)炒饭 10元 1)炒面 10元 1)猪肉大葱 18元
2)盖饭 10元 2)热干面 9元 2)素三鲜 15元
3)拌饭 12元 3)烩面 15元 3)韭菜鸡蛋 18元
4)返回主菜单 4)重庆小面 9元 4)返回主菜单
5)返回主菜单
选择后,提示用户,再吃几份,输入完后提示是否还要继续选,如继续选,则返回主菜单,然后继续以上过程,如不要继续选,则会打印消费单后退出,消费单格式如下
炒饭 5份 50元
热干面 1份 9元
素三鲜 1份 15元
总计 74元
折后 59.2元
#!/bin/bash
PS3=请您点餐: #定义select的输入格式
echo "消费满80打8折,亲!"
declare -a fen #定义份数数组
caidan=(炒饭 盖饭 拌饭 炒面 热干面 烩面 小面 猪肉大葱 素三鲜 韭菜鸡蛋) #定义菜单名数组
danjia=(10 10 12 10 9 15 9 18 15 18) #定义价格数组
while true ;do #定义永真循环方便循环跳出
select variable in 饭 面 饺子 不吃滚蛋 结账 #select列表,主菜单
do
case $REPLY in #定义饭子菜单
1)select riable in 炒饭 盖饭 拌饭 返回
do
case $REPLY in
1)echo "炒饭10元每份"
read -p 您要几份: fen[0]
break 2;; #跳出两层循环回到主菜单
2)echo "盖饭10元每份"
read -p 您要几份: fen[1]
break 2;;
3)echo "拌饭10元每份"
read -p 您要几份: fen[2]
break 2;;
4)break 2;;
esac
done;;
2)select riable in 炒面 热干面 烩面 小面 返回 #定义面子菜单
do
case $REPLY in
1)echo "炒面10元份"
read -p 您要几份: fen[3]
break 2;;
2)echo "热干面9元每份"
read -p 您要几份: fen[4]
break 2;;
3)echo "烩面15元每份"
read -p 您要几份: fen[5]
break 2;;
4)echo "小面9元每份"
read -p 您要几份: fen[6]
break 2;;
5)break 2;;
esac
done;;
3)select riable in 猪肉大葱 素三鲜 韭菜鸡蛋 返回 #定义饺子子菜单
do
case $REPLY in
1)echo "猪肉大葱18元每份"
read -p 您要几份: fen[7]
break 2;;
2)echo "素三鲜15元每份"
read -p 您要几份: fen[8]
break 2;;
3)echo "韭菜鸡蛋18元每份"
read -p 您要几份: fen[9]
break 2;;
4)break 2;;
esac
done;;
4)exit;; #退出菜单
5)echo "清单";a=0 #清单
for ((i=0;i<10;i++));do
if [ "${fen[$i]}" != "" ];then #判断fen[$i]是否非空,非空则证明点了该菜
echo "${caidan[$i]} ${danjia[$i]}/份 $[${fen[$i]}*${danjia[$i]}]元"
a=$[$a+$[${fen[$i]}*${danjia[$i]}]]
fi
done
echo "总计: $a"
if [ $a -ge 80 ];then #判断是否打折
echo "折后: $[$a*8/10]"
else
echo "折后: $[a]"
fi
exit;;
esac
done
done
例2:
写一个创建用户的脚本,要求如下
1.执行时会询问,请输入要创建的用户名称(当用户超时8秒不输入,提示超时并退出),脚本会检测用户名是否已经存在,若已存在,则提示用户已存在,是否要为其设置密码,如否,则继续回到第1步,询问用户另一个用户名。如是,进入第3步。
2.如第1步完成,则会创建指定用户,然后脚本继续问用户是否为新用户设置密码,如否,则返回第1步继续创建其他用户,如是,则进入第3步
3.为用户设置密码,要求密码要验证2次,2次一致才可通过。同时密码要满足复杂性要求,要求如下:
密码至少8个字符长度,密码必须包含 大写,小写字母,数字,和#@!,._ 这之中的三种字符。 如不满足,则提示用户密码太短或太简单,返回第3步。
且密码不能是 /usr/share/dict/words 已存在的字符,或是,则提示用户密码是个常见单词,然后返回第3步。
用户只能尝试设置新密码3次,若超过3次仍然没有设置出满足要求的密码,则直接返回第1步。
4.在任何步骤,只要输入exit均可退出脚本
#!/bin/bash while true;do read -p "请输入用户名:" name a=$(cat /etc/passwd |cut -d: -f1) for n in $a;do #判断用户名是否合法 if echo $name|grep "$n" &> /dev/null ;then echo "用户名不合法" continue 2 elif echo "$name" |egrep "[[:upper:]].{4,}";then true break 2 else echo "请输入首字母大写且高于5位的字符" continue 2 fi done done while true;do #判断性别是否合法 read -p "请输入性别male/female:" male case $male in male|female)break 2;; *)echo "输入错误请重新输入";continue 2;; esac done while true ;do #判断生日是否合法 read -p "请输入生日例YYYY-MM-DD:" bir if echo $bir|egrep "[[:digit:]]{4}(-[[:digit:]]{1,2}){2}" &> /dev/null;then true else echo "输入不合法";continue 2 fi bird=$(echo $bir|cut -d‘-‘ -f3) birm=$(echo $bir|cut -d‘-‘ -f2) biry=$(echo $bir|cut -d‘-‘ -f1) if cal $bird $birm $biry &> /dev/null;then break 2 else echo "输入不合法";continue 2 fi done while true;do #判断手机号是否合法 read -p "请输入手机号:" ph if echo $ph |egrep ‘\<1[3857][[:digit:]]{9}\>‘ &> /dev/null;then break else echo "格式不对" continue fi done while true;do #判断身份证号是否合法 read -p "请输入身份证号:" card echo $id |egrep ‘[[:digit:]]{17}[[:digit:]x]‘ &> /dev/null if [ $? -eq 0 ];then biry1=`echo $id |cut -c 7-10` birm1=`echo $id |cut -c 11-12` bird1=`echo $id |cut -c 13-14` if [ $(echo -n $birm|wc -m) -eq 1 ];then birm=0$birm fi if [ $(echo -n $bird|wc -m) -eq 1 ];then birm=0$bird fi if [ "$biry$birm$bird" == $biry1$birm1$bird1 ];then shu=$[$(echo $id|cut -c 17)%2] case $shu in 1)xingbie=male if [ "$xingbie" != "$sex" ];then echo "性别错了" continue else break fi;; *)xingbie=female if [ "$xingbie" != "$sex" ];then echo "性别错了" continue else break fi;; esac else echo "日期不符" continue fi else echo 格式不对 continue fi done echo $name:$male:$dete:$card >> /root/info.txt
例3:
1.执行时会询问,请输入要创建的用户名称(当用户超时8秒不输入,提示超时并退出),脚本会检测用户名是否已经存在,若已存在,则提示用户已存在,是否要为其设置密码,如否,则继续回到第1步,询问用户另一个用户名。如是,进入第3步。
2.如第1步完成,则会创建指定用户,然后脚本继续问用户是否为新用户设置密码,如否,则返回第1步继续创建其他用户,如是,则进入第3步
3.为用户设置密码,要求密码要验证2次,2次一致才可通过。同时密码要满足复杂性要求,要求如下:
密码至少8个字符长度,密码必须包含 大写,小写字母,数字,和#@!,._ 这之中的三种字符。 如不满足,则提示用户密码太短或太简单,返回第3步。
且密码不能是 /usr/share/dict/words 已存在的字符,或是,则提示用户密码是个常见单词,然后返回第3步。
用户只能尝试设置新密码3次,若超过3次仍然没有设置出满足要求的密码,则直接返回第1步。
4.在任何步骤,只要输入exit均可退出脚本
#!/bin/bash password() { #函数判断密码的合法性 for ((i=0;i<=2;i++));do b=0 read -p "请输入密码:" pass read -p "请确认密码:" rpass if echo $pass|grep [a-z] &> /dev/null;then b=$[$b+1] fi if echo $pass|grep [A-Z] &> /dev/null;then b=$[$b+1] fi if echo $pass|grep [\~\!\@\#\$\%\^\&\*] &> /dev/null;then b=$[$b+1] fi if echo $pass|grep [0-9] &> /dev/null;then b=$[$b+1] fi lens=$(echo $pass |grep -o .|wc -l) if [ "$pass" != "$rpass" ];then echo "两次密码不一致" elif [ $lens -lt 8 ];then echo "密码太短" echo "密码位数至少为8位" elif [ $b -lt 3 ];then echo "密码太过简单" echo "密码至少由大写,小写字母,数字,和特殊字符这之中的三种字符" elif cat /usr/share/dict/words | grep ".*$pass.*" &> /dev/null;then #写的有点问题,应该用字典过滤密码,不是用密码过滤字典 echo "密码中包含常用单词" else echo $pass |passwd --stdin $username &> /dev/null echo "密码修改成功" exit fi done } while true ;do read -p "请输入用户名:" -t 8 username #超时输入则退出 a=$(echo $?) if [ $a != 0 ];then echo echo "超时";exit fi if [ $username == exit ];then exit #输入exit退出 fi if id $username &> /dev/null ;then echo "该用户已存在" read -p "是否为其设置密码y/n:" b case $b in y|Y)password "$username";; #调用passwd函数 n|N)continue;; exit) exit;; #输入exit退出 esac else useradd $username read -p "是否为新用户设置密码y/n:" c case $c in y|Y)password "$username";; n|N)continue;; exit) exit;; esac fi
附:
eval命令
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量.该命令对变量进行两次扫描
创建临时文件
mktemp命令:创建并显示临时文件,可避免冲突
mktemp[OPTION]... [TEMPLATE]
TEMPLATE: filename.XXX
X至少要出现三个
OPTION:
-d: 创建临时目录
-p DIR或--tmpdir=DIR:指明临时文件所存放目录位置
示例:
mktemp/tmp/test.XXX
tmpdir=`mktemp–d /tmp/testdir.XXX`
mktemp--tmpdir=/testdirtest.XXXXXX
安装复制文件
install命令:
install [OPTION]... [-T] SOURCE DEST 单文件
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY...创建空目录
选项:
-m MODE,默认755
-o OWNER
-g GROUP
示例:
install -m 700 -o wang -g admins srcfile desfile
install –m –d /testdir/installdir
原文地址:https://www.cnblogs.com/angge/p/9469669.html