文章目录
条件选择
选择执行if语句
[root@leiRocky data]# help if
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
Execute commands based on conditional.
The `if COMMANDS' list is executed. If its exit status is zero, then the
`then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is
executed in turn, and if its exit status is zero, the corresponding
`then COMMANDS' list is executed and the if command completes. Otherwise,
the `else COMMANDS' list is executed, if present. The exit status of the
entire construct is the exit status of the last command executed, or zero
if no condition tested true.
Exit Status:
Returns the status of the last command executed.
单分支
if 判断条件; then
条件为真的分支代码
fi
双分支
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
多分支
if 判断条件1; then
条件1为真的分支代码
elif 判断条件2; then
条件2为真的分支代码
elif 判断条件3; then
条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi
说明:
1.多个条件时,逐个条件进行判断,第一次遇为“真条件时,执行其分支,而后结束整个if语句
2. if 语句可嵌套
判断身体质量指数(BMI)
BMI计算公式:
BMI=体重(以千克为单位)除以身高的平方(以米为单位)。
例如:一个人的身高为1.75米,体重为68千克,他的BMI=68/(1.75*1.75)=22.2。
中国成人正常的BMI应在18.5-23.9之间,如果小于18.5为体重不足,如果大于等于24为超重,大于等于28为肥胖。
vim if_bmi.sh
#! /bin/bash
read -p "请输入身高(m为单位)∶" HIGH
if [[ ! "$HIGH" =~ ^[0-2](\.[0-9]{,2})?$ ]]; then
echo "输入错误的身高!"
exit 1
fi
read -p "请输入体重kg为单位:" WEIGHT
if [[ ! "$WEIGHT" =~ ^[0-9]{1,3}$ ]]; then
echo "输入错误的体重! ";
exit 2;
fi
BMI=`echo $WEIGHT/$HIGH^2|bc`
if [ $BMI -le 18 ]; then
echo "太瘦了,多吃点!"
elif [ $BMI -lt 24 ]; then
echo "身材很棒!"
else
echo "太胖了,注意节食,加强运动!"
fi
脚本调错
bash -x 可以一行一行的调试脚本。
bash -x if_bmi.sh
条件判断case语句
[root@leiRocky scripts]# help case
case: case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
Execute commands based on pattern matching.
Selectively execute COMMANDS based upon WORD matching PATTERN. The
`|' is used to separate multiple patterns.
Exit Status:
Returns the status of the last command executed.
case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
默认分支
;;
esac
case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如:a|b
范例
case_yesorno.sh
#! /bin/bash
read -p "Do you agree(yes/no)? " INPUT
INPUT=`echo $INPUT | tr 'A-Z' 'a-z'`
case $INPUT in
y|yes)
echo "You input is YES"
;;
n|no)
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
esac
case_yesorno2.sh
#! /bin/bash
read -p "Do you agree(yes/no)? " INPUT
case $INPUT in
[yY]|[Yy][Ee][Ss])
echo "You input is YES"
;;
[Nn]|[Nn][Oo])
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
esac
范例:文件后缀处理
vim file_suffix.sh
#! /bin/bash
read -p "please input a file: " FILE
SUFFIX=`echo $FILE | grep -Eo "[^.]+$"`
case $SUFFIX in
gz)
echo gzip
;;
bz2)
echo bzip2
;;
xz)
echo xz
;;
z)
echo compress
;;
zip)
echo zip
;;
*)
echo other
;;
esac
运维菜单实现版本V2
vim sre_meun.sh
#! /bin/bash
echo -en "\E[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF
echo -en '\E[Om'
read -p "请输入上面数字1-5: " MENU
case $MENU in
1)
echo "执行备份数据库"
./backup.sh
;;
2)
echo "清理日志"
;;
3)
echo "软件升级"
;;
4)
echo "软件回滚"
;;
5)
echo "删库跑路"
;;
*)
echo "INPUT FALSE!"
esac
循环
将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件。
重复运行次数
循环次数事先已知
循环次数事先未知
常见的循环的命令: for, while, until
#Centos7的for帮助比Centos8的全面
[root@centos7 ~]# help for
for: for NAME [in WORDS ... ] ; do COMMANDS; done
Execute commands for each member in a list.
The `for' loop executes a sequence of commands for each member in a
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
assumed. For each element in WORDS, NAME is set to that element, and
the COMMANDS are executed.
Exit Status:
Returns the status of the last command executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
Arithmetic for loop.
Equivalent to
(( EXP1 ))
while (( EXP2 )); do
COMMANDS
(( EXP3 ))
done
EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is
omitted, it behaves as if it evaluates to 1.
Exit Status:
Returns the status of the last command executed.
for循环
格式1
do和done可以看成一对花括号{}, do是“{”开始,done是“}”结束,do和done中间包裹着循环体;
方式1
for NAME [in WORDS ...] ; do COMMANDS; done
# do和done可以看成一对花括号{}, do是{开始,done是}结束,do和done中间包裹着循环体;
方式2
for 变量名 in 列表; do
循环体
done
方式3
for 变量名 in 列表
do
循环体
done
for i in 1 2 3 4 5 6 ; do echo i=$i; done
执行机制:
·依次将列表中的元素赋值给"变量名";每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束
·如果省略[in WORDS...],此时使用位置参数变量 in "$@"
for循环列表生成方式:
1.直接给出列表
2.整数列表:
{start..end}
$(seq [start [step]] end)
3.返回列表的命令:
$(COMMAND)
4.使用glob, 如: *.sh
5.变量引用, 如:$@, $*, $#
范例:面试题,计算1+2+3+…+100的结果
sum=0; for i in {1..100}; do let sum+=i;done ; echo sum=$sum
seq -s+ 100 |bc
echo {1..100}|tr ' ' +|bc
seq 100|paste -sd +|bc
九九乘法表
一步步来,先打印一行
#! /bin/bash
for i in {1..9};do
echo -n "${i}x9=$((i*9)) ";
done
echo
再打印列
#! /bin/bash
for i in {1..9};do
for j in `seq $i`;do
echo -e "${i}x${j}=$((i*j))\t\c ";
done
echo
done
生产题,修改所有文件的后缀名
生产案例:将指定目录下的文件所有文件的后缀改名为bak后缀
怎么区文件的前缀和后缀?
echo leilei.jpg | sed -En 's/^(.*)\.([^.]+)$/\2/p'
vim for_rename.sh
#! /bin/bash
DIR=/data/test
cd $DIR || { echo 无法进入 $DIR; exit 1; }
for FILE in *; do
PRE=`echo $FILE|grep -Eo ".*\."`
mv $FILE ${PRE}bak
# PRE=`echo $FILE |rev|cut -d. -f 2-| rev`
# PRE=`echo $FILE | sed -nr 's/(.*)\.([^.]+)$/\1/p'`
# SUFFIX=`echo $FILE | sed -nr 's/(.*)\.([^.]+)$/\2/p'`
# mv $FILE $PRE.bak
done
面试题,移动所有目录
M37期面试题,要求将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下
1.创建YYYY-MM-DD格式的目录,当前日期1年 365天到目前共365个目录,里面有10个文件.log后缀的文件
[root@centos7 ~]# date
Thu Aug 8 18:52:57 CST 2024
[root@centos7 ~]# date -d '' +%F
2024-08-08
[root@centos7 ~]# date -d '-1 day' +%F
2024-08-07
[root@centos7 ~]# date -d '+1 month' +%F
2024-09-08
[root@centos7 ~]# date -d '-1 year' +%F
2023-08-08
[root@centos7 ~]#
#! /bin/bash
PDIR=/data/test
for i in {1..356};do
DIR=`date -d "-$i day" +%F`
mkdir -pv $PDIR/$DIR
cd $PDIR/$DIR
for j in {1..10};do
touch $RANDOM.log
done
done
2.将上面的目录移动到YYYY-MM/DD/下
vim move_dir.sh
#! /bin/bash
DIR=/data/test
cd $DIR || { echo 无法进入 $DIR; exit 1; }
for subdir in *; do
YYYY_MM=`echo $subdir |cut -d"-" -f1,2`
DD=`echo $subdir |cut -d"-" -f3`
[ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD &> /dev/null
mv $subdir/* $YYYY_MM/$DD
done
rm -rf $DIR/*-*-*
面试题:扫描一个网段,判断主机的状态,打印出在线的主机。
#! /bin/bash
NET=192.168.10
for ID in {1..254};do
{
ping -c1 -w1 $NET.$ID &> /dev/null && echo $NET.$ID is up || echo $NET.$ID is down
}&
done
wait
格式2
双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格的变量操作.也像Java的风格。
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
for (( 控制变量初始化;条件判断表达式;控制变量的修正表达式));
do
循环体;
done
计算从1加到100的和
vim sum.sh
#! /bin/bash
for ((sum=0,i=1;i<=100;i++));do
let sum+=i;
done
echo sum=$sum
九九乘法表
先循环9行试试
#! /bin/bash
for((i=1;i<=9;i++));do
echo "${i}X9=$((i*9))"
done
再循环9列试试
#!/bin/bash
for((i=1;i<=9;i++));do
for((j=1;j<=i;j++));do
echo "${j}X${i}=$((i*j))"
done
echo
done
#!/bin/bash
for((i=1;i<=9;i++));do
for((j=1;j<=i;j++));do
echo -e "${j}X${i}=$((i*j))\c"
done
echo
done
#!/bin/bash
for((i=1;i<=9;i++));do
for((j=1;j<=i;j++));do
echo -e "${j}X${i}=$((i*j))\t\c"
done
echo
done
while循环
[root@rocky ~]# help while
while: while COMMANDS; do COMMANDS; done
Execute commands as long as a test succeeds.
Expand and execute COMMANDS as long as the final command in the
`while' COMMANDS has an exit status of zero.
Exit Status:
Returns the status of the last command executed.
格式
while COMMANDS; do COMMANDS; done
while COMMANDS; do
循环体;
done
说明:
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;
条件为"true",则执行一次循环;直到条件测试状态为"false"终止循环,
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false
无限循环
while true; do
循环体
done
while : ; do
循环体
done
范例:
求从1加到100的和
#!/bin/bash
sum=0
i=1
while (($i<=100));do
sum=$((sum +i))
i=$((i+1))
done
echo $sum
监控分区磁盘使用率
扫描"/dev/nv*"开头的磁盘分区,使用率达到15%时就报警输出实际占用率,脚本这里是每10秒就打印输出一次
#!/bin/bash
WARNING=15
while true;do
df | sed -rn '/^\/dev\/nv/s#.* ([0-9]+)%.*#\1#p' | while read use ;do
if [ $use -gt $WARNING ];then
echo $use
fi
done
sleep 10
done
until循环
和while差不多,循环条件有差异
[root@rocky ~]# help until
until: until COMMANDS; do COMMANDS; done
Execute commands as long as a test does not succeed.
Expand and execute COMMANDS as long as the final command in the
`until' COMMANDS has an exit status which is not zero.
Exit Status:
Returns the status of the last command executed.
格式
until: until COMMANDS; do COMMANDS; done
until: until COMMANDS; do
循环体;
done
说明:
进入条件:CONDITION为false
退出条件:CONDITION为true
无限循环
until false; do
循环体
Done
#! /bin/bash
sum=0
i=1
until (($i>100));do 看清楚哦$i>100,是大于100哦
sum=$((sum +i))
i=$((i+1))
done
echo $sum
循环控制语句
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
continue
[root@rocky ~]# help continue
continue: continue [n]
Resume for, while, or until loops.
Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop.
If N is specified, resumes the Nth enclosing loop.
Exit Status:
The exit status is 0 unless N is not greater than or equal to 1.
格式:
while CONDITION1; do
CMD1
...
if CONDITION2 ; then
continue
fi
CMDn
...
done
continue 1:结束内层
#!/bin/bash
for((i=0;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && continue 1
echo $j
done
echo "----------------"
done
continue 2:结束外层
#!/bin/bash
for((i=0;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && continue 2
echo $j
done
echo "----------------"
done
break
break [N]:提前结束第N层整个循环,最内层为第1层
[root@rocky ~]# help break
break: break [n]
Exit for, while, or until loops.
Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing
loops.
Exit Status:
The exit status is 0 unless N is not greater than or equal to 1.
格式:
while CONDITION1; do
CMD1
...
if CONDITION2; then
break
fi
CMDn
...
done
break 1:内层循环
#!/bin/bash
for((i=0 ;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && break
echo $j
done
echo -----------
done
break 2:结束这个循环
#!/bin/bash
for((i=0 ;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && break 2
echo $j
done
echo -----------
done
break结束点菜结账
#!/bin/bash
sum=0
COLOR='echo -e \033[1; 31m'
COLOR2='echo -e \033[1; 32m'
END="\033[0m"
while true ;do
echo -e "\033[33;1m\c"
cat <<-EOF
1)鲍鱼
2)满汉全席
3)龙虾
4)燕窝
5)帝王蟹
6)点菜结束,结帐
EOF
echo -e "\033[0m"
read -p "请点菜(1-6): " MENU
case $MENU in
1|4)
$COLOR'菜价: $10'$END
let sum+=10
;;
3|5)
$COLOR'菜价:$20'$END
let sum+=20
;;
2)
$COLOR'菜价:$200000'$END
let sum+=200000
;;
6)
$COLOR2"你点的菜总价格是人\$$sum" $END
break
;;
*)
echo "点错了,没有这道菜"
;;
esac
$COLOR2"你点的菜总价格是 \$$sum" $END
done
shift命令
shift [n] 用于将参量列表list左移指定次数,缺省为左移一次。
参量列表list一旦被移动,最左端的那个参数就从列表中删除。while循环遍历位置参量列表时,常用到shift
[root@rocky scripts]# help shift
shift: shift [n]
Shift positional parameters.
Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is
not given, it is assumed to be 1.
Exit Status:
Returns success unless N is negative or greater than $#.
循环与菜单select
[root@rocky scripts]# help select
select: select NAME [in WORDS ... ;] do COMMANDS; done
Select words from a list and execute commands.
The WORDS are expanded, generating a list of words.
The set of expanded words is printed on the standard error, eachpreceded by a number.
If `in WORDS' is not present, `in "$@"'is assumed.
The PS3 prompt is then displayed and a line read from the standard input.
If the line consists of the number corresponding to one of the displayed words,
then NAME is set to that word. If the line is empty, WORDS and the prompt are redisplayed.
If EOF is read, the command completes. Any other value read causes NAME to be set to null.
The line read is saved in the variable REPLY.
COMMANDS are executed after each selection until a break command is executed.
Exit Status:
Returns the status of the last command executed.
格式
select NAME [in WORDS ... ;] do COMMANDS; done
select NAME in list ; do
循环体命令;
done
说明
1.select循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准错误上,并显示PS3提示符,等待用户输入
2.用户输入菜单列表中的某个数字,执行相应的命令
3.用户输入菜单列表中的某个数字,会将对应的WORD值赋值给NAME变量
4.用户输入被保存在内置变量REPLY中
5.select是个无限循环,因此要用break 命令退出循环,或用exit 命令终止脚本。也可以按ctrl+c退出循环
6.select经常和case联合使用
7.与for循环类似,可以省略in list,此时使用位置参量
select点菜
#!/bin/bash
sum=0
PS3="请点菜(1-6): "
select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do
case $REPLY in
1)
echo $MENU 价格是 ¥100
let sum+=100
;;
2)
echo $MENU 价格是 ¥88
let sum+=88
;;
3)
echo $MENU价格是 ¥66
let sum+=66
;;
4)
echo $MENU 价格是 ¥166
let sum+=166
;;
5)
echo $MENU 价格是 ¥200
let sum+=200
;;
6)
echo "点菜结束,退出"
break
;;
*)
echo "点菜错误,重新选择"
;;
esac
done
echo "总价格是: $sum"