条件语句
1、测试
使用[]时要使用空格,注意格式
格式1:test 条件表达式
格式2:[ 条件表达式 ]#注意空格
注意[]空格,否则会失败
测试 是否成功使用 $?返回值来判断
[ 操作符 文件或目录 ]
help test
操作符:
-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件
属性测试补充:
-s FILE #是否存在且非空
-t fd #fd 文件描述符是否在某终端已经打开
-N FILE #文件自从上一次被读取之后是否被修改过
-O FILE #当前有效用户是否为文件属主
-G FILE #当前有效用户是否为文件属组
条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程,实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
条件测试命令
例子
[root@test1 ~]# test -d /etc/sysconfig
[root@test1 ~]# echo $?
0
[root@test1 ~]# test -f /etc/sysconfig
[root@test1 ~]# echo $?
1
[root@test1 ~]# [ -d /etc/sysconfig/ ] 注意前后空格
[root@test1 ~]# echo $?
0
[root@test1 ~]# [ -f /etc/sysconfig/ ]
[root@test1 ~]# echo $?
1
[root@localhost ~]# test -e qiuhe.sh &&echo "yes"
yes
&&表示且的意思 前面的表达式成立才会输出yes
[root@localhost ~]#ll /etc/shadow
---------- 1 root root 1549 10月 19 10:58 /etc/shadow
[root@localhost ~]#[ -r /etc/shadow ]
[root@localhost ~]#echo $?
0
#实际效果,不是表面显示,注意root权限
[root@localhost ~]#[ -x /etc/shadow ]
[root@localhost ~]#echo $?
1
#root执行权限别人没有root也没有,别人有root也有
###a 和 e 的区别
[root@localhost ~]#[ ! -e /etc/shadow ]
[root@localhost ~]#echo $?
1
[root@localhost ~]#[ ! -a /etc/shadow ]
[root@localhost ~]#echo $?
0
##建议使用e选项
1.2 比较整数数值
[ 整数1 操作符 整数2 ] 公式
-
-eq:第一个数等于(Equal)第二个数
-
-ne:第一个数不等于(Not Equal)第二个数
-
-gt:第一个数大于(Greater Than)第二个数
-
-lt:第一个数小于(Lesser Than)第二个数
-
-ge:第一个数大于或等于(Greater or Equal)第二个数
-
-le:第一个数小于或等于(Lesser or Equal)第二个数
[root@31yml opt]#a=1
[root@31yml opt]#b=4
[root@31yml opt]#[$a -eq $b]
bash: [1: 未找到命令...
[root@31yml opt]#[ $a -eq $b ]#距离两侧括号一定要有空格
1.3 字符串比较
常用的测试操作符
-
= 字符串内容相同
-
!= 字符串内容不同,! 号表示相反的意思
-
-z 字符串内容为空
-
-n 字符是否存在
格式
[ 字符串1 = 字符串2 ] 是否相同
[ 字符串1 != 字符串2 ] 是否不相同
[ -z 字符串 ] 是否为空
[ -n 字符串 ] 字符是否存在
[root@31yml opt]#str1=wang
[root@31yml opt]#str2=zhou
[root@31yml opt]#[ $str1 = $str2 ]
[root@31yml opt]#echo $?
1
[root@31yml opt# [ $USER = root ]&& echo true
true
[root@31yml opt]# [ $USER != root ]&& echo true
[root@31yml opt]# read -p "yes/no:" ack
yes/no:
[root@31yml opt]# echo $ack
[root@31yml opt]# [ -z $ack ] && echo true
true
1.4 逻辑操作
格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ... 格式2:命令1 操作符 命令2 ...
常见条件
-
-a或&&:逻辑与,“而且”的意思全真才为真——如果第一个为假,整个就为假
-
-o或||:逻辑或,“或者”的意思一真即为真——第一个为真,不用执行第二个;第一个为假,才需执行第二个
-
!:逻辑否
[root@31yml ~]# uname -r
3.10.0-693.el7.x86_64
[root@31yml ~]# uname -r |awk -F. '{print $1}'
3
[root@31yml ~]# uname -r |awk -F. '{print $2}'
10
[root@31yml ~]# MAIN=$(uname -r |awk -F. '{print $2}')
[root@31yml ~]# SAIN=$(uname -r |awk -F. '{print $1}')
[root@31yml ~]# [ $SAIN -ge 3 ]&& [ $MAIN -ge 4 ]&& echo "yes"
yes
[root@31yml ~]# [ ! -d mmm ] && echo "yes"
yes
[root@31yml etc]# [ 4 -lt 5 ]&&echo true || echo false
true
[root@31yml etc]# [ 4 -gt 5 ]&&echo true || echo false
false
[root@31yml etc]# [ 4 -gt 5 ]&& echo true ||echo false
false
|| 只有前面不成立时才会执行后面的操作
合并条件
[root@31yml etc]# [ $a -ne 1 ]&&[ $a != 2 ]
[root@31yml etc]# echo $?
0
[root@31yml etc]# [ $a -ne 1 -a $a != 2 ]
[root@31yml etc]# echo $?
0
[root@31yml etc]# [[ $a -ne 1 && $a != 2 ]]
[root@31yml etc]# echo $?
0
ping 小脚本
-c 发送包的个数
-i 发送的间隔时间
-W 超时时间
-w 多少秒后停止ping操作
#!/bin/bash
ping -c 3 -i 0.5 -W2 $1 &> /dev/null && echo "$1 online" || echo "$1 off"
#注意w大写
[root@31yml opt]# df -h |grep "/dev/sd" |awk -F "[ %]+" '{print $5}'
4
[root@31yml opt]# df -h |grep "/dev/sd" |awk '{print $5}'
4%
[root@31yml opt]# df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}'
4
[root@31yml opt]# use=$(df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}')
[root@31yml opt]# echo $use
4
[root@31yml opt]# [ $use -gt 80 ] && echo "磁盘占用太多了" || echo "目前磁盘使用较少"
#1 打开qq邮箱,设置->账户->POP3/SMTP,开启服务
[root@31yml ~]#echo test |mail -s test [email protected]
#发送邮件
#!/bin/bash
use=$(df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}')
[ $use -gt 80 ]&& echo "磁盘使用量过高" | mail -s warning [email protected] ||echo "磁盘使用量正常"
#!/bin/bash
use=80
disk=`df|grep "sd"|tr -s " "|cut -d " " -f5|cut -d "%" -f1`
[ $disk -ge $use ] && echo "磁盘使用率过高"|mail -s test [email protected]
1.5 双中括号
[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式
两侧一样要空格,在比较括号里就要用空格
#通配符
[root@31yml ~]#FILE=test.log
[root@31yml ~]#[[ "$FILE" == *.log ]]
[root@31yml ~]#echo $?
0
[root@31yml ~]#FILE=test.txt
[root@31yml ~]#[[ "$FILE" == *.log ]]
[root@31yml ~]#echo $?
1
[root@31yml ~]#[[ "$FILE" != *.log ]]
[root@31yml ~]#echo $?
0
1.6 () {}
两者都可以将多个命令组合在一起,批量执行
#()会开启子shell
root@31yml opt]#echo $BASHPID
16708
[root@31yml opt]#(echo $BASHPID;)
21921
#{ } 不会开启子shell
[root@31yml opt]#echo $BASHPID
16708
[root@31yml opt]#{ echo $BASHPID; }
16708
#格式
[root@31yml opt]#(cd /opt;ls)
1.sh 2.sh 3.sh bc.txt
[root@31yml opt]#{cd /opt;ls}
bash: {cd: 未找到命令...
bash: ls}: 未找到命令...
[root@31yml opt]#{ cd /opt;ls }#左侧要空格,命令结尾要用;,不然就是用括号多行输入
> }
ls: 无法访问}: 没有那个文件或目录
[root@31yml opt]#{ cd /opt;ls; }
1.sh 2.sh 3.sh bc.txt
[root@31yml opt]#{ cd /opt;ls;}
1.sh 2.sh 3.sh bc.txt
[root@31yml opt]#{cd /opt;ls;}
bash: 未预期的符号 `}' 附近有语法错误
2、if语句的结构
2.1 分支结构
单分支
if 判断条件;
then 条件为真的分支代码
fi
双分支
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
多分支
if 判断条件1
then
条件1为真的分支代码
elif 判断条件2
then
条件2为真的分支代码
elif 判断条件3;then
条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi
#举例子
#单分支
###########判断是否为超级管理员#######################
#!/bin/bash
if [ "$USER" != "root" ]
then
echo "非管理员用户无权限操作"
else
echo "是管理员用户"
fi
###########判断是主机连通性#######################
#!/bin/bash
ping -c 3 192.168.91.1
if
[ $? = 0 ]
then
echo "与真机网络通顺"
exit 1
fi
echo "与真机网络不通"
#######################多分支#######################
#!/bin/bash
read -p "请输入你的考试分数:" grade
if [ $grade -ge 85 ]&& [ $grade -le 100 ]
then
echo "你的成绩为$grade"
echo "你的成绩为优秀"
elif [ $grade -ge 70 ]&&[ $grade -le 84 ]
then
echo "你的成绩为$grade"
echo "你的成绩为良好"
elif
[ $grade -ge 60 ]&&[ $grade -le 69 ]
then
echo "你的成绩为$grade"
echo "你的成绩为合格"
else
echo "你的成绩为$grade"
echo "你的成绩不合格"
fi
#!/bin/bash
h=`date +%H`
if [ $h -ge 6 -a $h -le 10 ];then
echo "早上好"
elif [ $h -ge 11 -a $h -le 13 ];then
echo "中午好"
elif [ $h -ge 14 -a $h -le 18 ];then
echo "下午好"
else
echo "晚上好"
fi
#鸡兔同笼,是中国古代著名典型趣题之一,记载于《孙子算经》之中。
#今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?
#!/bin/bash
head=35
foot=94
94-2*35=24/2=12=兔子数量
2.2 case结构
case 变量值 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
*)
默认命令序列
esac
#case对应esac
#命令序列对应;;
case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[0-9] 指定范围内的任意单个字符
| 或者,如: a|b
例子:
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
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
#!/bin/bash
read -p "请输入你的分数" score
case $score in
100)
echo "$score 你太优秀了"
;;
[89][0-9])
echo "$score 表现不错"
;;
[67][0-9])
echo "$score 你及格了"
;;
[0-9]|[1-5][0-9])
echo "$score 你不及格"
;;
*)
echo "输入有误"
esac
#!/bin/bash
m=`echo $[RANDOM%3+1]`
read -p "请输入 1.石头2.剪刀3.布:" h
if [ $m -eq $h ]
then
echo "打成平局"
bash $0
elif [ $h -eq 1 -a $m -eq 2 -o $h -eq 2 -a $m -eq 3 -o $h -eq 3 -a $m -eq 1 ]
then
echo "人类胜利"
else
echo 机器胜利
fi
#!/bin/bash
key=`echo $[RANDOM%3+1]`
read -p "请输入1包子 2剪子 3 锤子:" num
case $num in
1)
num="包子"
;;
2)
num="剪子"
;;
3)
num="锤子"
;;
*)
echo "你输错了!"
exit
;;
esac
case $key in
1)
key="包子"
;;
2)
key="剪子"
;;
3)
key="锤子"
;;
esac
if [ $num = "包子" -a $key = "锤子" -o $num = "剪子" -a $key = "包子" -o $num = "锤子" -a $key = "剪子" ]
then
echo 机器出的是$key
echo 你出的是$num
echo "人类胜利"
elif [ $num = $key ]
then
echo 机器出的是$key
echo 你出的是$num
echo "打成平局再来一次"
else
echo 机器出的是$key
echo 你出的是$num
echo "机器胜利"
fi
跳板机
#!/bin/bash
web1="192.168.91.101"
mysql="192.168.91.102"
docker="192.168.91.103"
#打印菜单#多行输出
cat <<EOF
1.web1
2.mysql
3.doker
EOF
read -p "请输入数字(1-3):" num
case $num in
1)
ssh $web1
;;
2)
ssh $mysql
;;
3)
ssh $doker
;;
esac
循环语句
echo
echo -n 表示不换行输出
echo -e 表示输出转义符
常用的转义符
选项 | 作用 |
---|---|
\r | 光标移至行首,并且不换行 |
\s | 当前shell的名称,如bash |
\t | 插入Tab键,制表符 |
\n | 输出换行 |
\f | 换行,但光标仍停留在原处 |
\ | 表示插入"\"本身转义 |
\b | 表示退格 不显示前一个字符 |
\c | 抑制更多的输出或不换行 |
[root@31yml opt]#echo -e "12345\b678"
##退格删除前面的字符
1234678
[root@31yml opt]#echo -e "12345\b\b678"
123678
[root@31yml opt]#echo -e "12345\b\b\b678"
12678
[root@31yml opt]#echo -e "12345\b\b\b\b678"
16785
###注意退格键和末尾的字符相关,超过末尾的字符数量 会出bug 了解即可
[root@31yml opt]#echo -e "12345678\c"
12345678[root@31yml opt]#echo -e "1234\c5678"
1234[root@31yml opt]#
###\c 注意 使用在数字中间会把后面内容删除
echo -e "n\n\n\n\n\nw"|fdisk /dev/sdb
#自动硬盘分区
#不同格式不同含义
[root@localhost data]#rm -rf 123
#是把软连接删除
[root@localhost data]#rm -rr 123/
#把软连接里的文件全删除
date
date查看当前系统时间
-d 你描述的日期,显示指定字符串所描述的时间,而非当前时间
%F 完整日期格式,等价于 %Y-%m-%d
% T 时间(24小时制)(hh:mm:ss)
[root@31yml opt]#date
2023年 08月 20日 星期日 17:04:56 CST
[root@31yml opt]#date -d '-1 day'+%F #F代表full
date: 无效的日期"-1 day+%F"
[root@31yml opt]#date -d '-1 day' +%F
2023-08-19
[root@31yml opt]#date +%F
2023-08-20
[root@31yml opt]#date -d "1 day" +%F-%T
2023-08-21-17:05:56
[root@31yml opt]#date -d "+3 day"
2023年 08月 23日 星期三 17:06:19 CST
[root@31yml opt]#date -d "-3 day"
2023年 08月 17日 星期四 17:06:22 CST
[root@31yml opt]#date -d "1 day" +%F' '%T
2023-08-21 17:06:54
[root@31yml opt]#date -d "1 day" +%F'~~'%T
2023-08-21~~17:07:02
循环含义
将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
重复运行次数
-
循环次数事先已知
-
循环次数事先未知
常见的循环的命令:for, while, until
for
for (已知循环次数)
for 名称 [in 词语 ...];do 命令;done
for (( 表达式1;表达式2;表达式3 )); do 命令; done
expr1:定义变量并赋值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出
例子
#打印一行*
#!/bin/bash
for i in {1..9}
do
echo -e " * "
done
#打印正方形
#!/bin/bash
for j in `seq 9`
do
for i in {1..9}
do
echo -e " * \c"
#\c换行
done
echo
#换行
done
while
while(未知循环次数)
需要知道循环次数
while true
while ;;
while :
#死循环
while
#当命令判断为假时停止
例子
while true
do
read -p "请输入商品的价格1-1000:" num
let t++
if [ $num -eq $p ]
then
echo "恭喜你猜中了,实际价格是$p"
echo "您一共猜了${t}次"
exit 0
elif [ $num -gt $p ]
then
echo "您猜的价格高了"
else
echo "您猜的价格低了"
fi
done
until
until(未知循环次数)
until
#当命令判断为真时停止
例子
#!/bin/bash
i=0
sum=0
until [ $i -gt 100 ]
do
let sum+=$i
let i++
done
echo $sum
break
(跳出循环)
break num 表示跳出num层循环
continue
中止某次循环,但是不会完全终止命令
菜单
SELECT
[root@localhost data]#help select
select: select NAME [in 词语 ... ;] do 命令; done
从列表中选取词并且执行命令。
WORDS 变量被展开,生成一个词的列表。展开的词集合被打印
在标准错误输出设备上,每个以一个数字做前缀。如果没有 `in WORDS'
则假定使用`in "$@"'。PS3提示符会被显示并且从标准输入读入一行
如果该行由被显示的词对应的数字组成,则 NAME 变量被设定为相应
的词。如果行为空,则 WORDS 变量和提示符被重新显示。如果读取了
文件结束符,则命令完成。读入任何其他的值会导致 NAME 变量被设定
为空。读入的行被存放在变量 REPLY 中。COMMANDS 命令在每次选择
之后执行直到执行一个 break 命令。
退出状态:
返回最后一个执行的命令的状态。
一定要使用$REPLY
[root@localhost data]#select menu in 配置网卡 配置yum源;do echo $REPLY;done
#与for相似
[root@localhost data]#select menu in 配置网卡 配置yum源;do echo $menu;done
PS3="请选择功能(1-2)";select menu in 配置网卡 配置yum源;do echo $menu;done
PS3="请选择功能(1-2):";select menu in 配置网卡 配置yum源;do echo $menu;done
ps2=
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $REPLY;done
1) 配置网卡
2) 配置yum源
#? 1
1
#? 2
2
#? ^C
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
#? 1
配置网卡
#? 2
配置yum源
PS1 提示符
PS2 多行重定向
PS3 菜单选择
PS3
#!/bin/bash
sum=0
PS3="请输入(1-6):"
MENU="
宫保鸡丁
酸菜鱼
鱼香肉丝
佛跳墙
水煮肉片
点菜结束
"
select menu in $MENU
do
case $REPLY in
1)
echo $menu 价格是20
let sum+=20
;;
2)
echo $menu 价格是60
let sum+=60
;;
3)
echo $menu 价格是25
let sum+=25
;;
4)
echo $menu 价格是150
let sum+=150
;;
5)
echo $menu 价格是60
let sum+=60
;;
6)
echo "点菜结束"
break
;;
*)
echo "点菜错误,请重新选择"
;;
esac
done
echo "总价是$sum"
多行注释
cat >> <<EOF
EOF
#!/bin/bash
set_alias(){
cat >>~/.bashrc <<EOF
alias scandisk="echo '- - -'> /sys/class/scsi_host/host0/scan;echo '- - -'> /sys/class/scsi_host/host1/scan;echo '- - -'> /sys/class/scsi_host/host2/scan"
alias myvim="vim /etc/sysconfig/network-scripts/ifcfg-ens33"
EOF
}
disable_selinux(){
sed -ri.bak 's/^(SELINUX=).*/\1disabled/' /etc/selinux/config
}
disable_firewalld(){
systemctl disable --now firewalld &>/dev/null
echo -e "已禁用防火墙"
}
PS3="请选择(1-4):"
select menu in 关闭防火墙 修改别名 关闭selinux 退出
do
case $REPLY in
1)
disable_firewalld
;;
2)
set_alias
source ~/.bashrc
;;
3)
disable_selinux
;;
4)
break
;;
*)
echo "输入错误"
esac
done
[root@localhost data]#bash menu.sh
1) 关闭防火墙
2) 修改别名
3) 关闭selinux
4) 退出
请选择(1-4):2
|
ls | xargs
标准输入
标签:语句,脚本,shell,echo,31yml,&&,opt,root,bash
From: https://www.cnblogs.com/bacolate/p/17644837.html