数值运算与if条件判断

5381 字
27 分钟
数值运算与if条件判断

数值运算&&if条件判断#

[TOC]


📦 变量子串#

长度统计#

统计字符串的长度(笔试题)#

三种统计字符串长度的方法:

Terminal window
1)wc -L
'-L vs -l:小写 -l 是行数,大写 -L 是最长行长度'
[root@shell ~]# name=oldboy
[root@shell ~]# echo $name
oldboy
[root@shell ~]# echo $name | wc -L
6
2)awk length
[root@shell ~]# echo $name | awk '{print length}'
6
3)子串统计长度 — ${#变量名} ✅ 最常用
[root@shell ~]# echo ${#name}
6
Tip

📌 ${#变量名} 是 bash 内置语法,==效率最高==,推荐使用

统计长度小于 3 的字符串#

1)for 循环 + ${#i}
[root@shell ~]# cat for.sh
#!/bin/bash
for i in I am lizhenya I am 18
# 不能加引号,不然会变成一个整体
do
echo $i
done
[root@shell ~]# sh for.sh
I
am
lizhenya
I
am
18
2)输出每个字符的长度 & 并比较
# 只输出长度小于 3 的字符串
[root@shell ~]# cat for.sh
#!/bin/bash
for i in I am lizhenya I am 18
do
[ ${#i} -lt 3 ] && echo $i
done
[root@shell ~]# sh for.sh
I
am
I
am
18

扩展 — 用三剑客实现同样的效果

Terminal window
1)xargs + awk
[root@shell ~]# echo I am lizhenya I am 18 | xargs -n1
I
am
lizhenya
I
am
18
[root@shell ~]# echo I am lizhenya I am 18 | xargs -n1 | awk '{print length}'
1
2
8
1
2
2
[root@shell ~]# echo I am lizhenya I am 18 | xargs -n1 | awk '{if(length<3) print}'
I
am
I
am
18
2)纯 awk
'NF --> 每行有多少列' # 默认以空格分开
[root@shell ~]# echo I am lizhenya I am 18 | awk '{for(i=1;i<=NF;i++) if(length($i)<3) print $i}'
给i一个初值,$i为每一列字符 ⚠️ 中间是分号
I
am
I
am
18

子串删除#

从前往后删除#

Terminal window
[root@shell ~]# url=www.baidu.com
[root@shell ~]# echo $url
www.baidu.com
[root@shell ~]# echo ${#url}
13
⚠️ #号 在前面是统计字符串长度 ⚠️
'依旧是{ 花括号 }'
1)# 匹配 — 删除最短匹配(从前往后)
[root@shell ~]# echo ${url#www.}
baidu.com
# '删掉了开头的 www.'
[root@shell ~]# echo ${url#w}
ww.baidu.com
'只删了第一个 w,# 是懒惰匹配(最短)'
[root@shell ~]# echo ${url#*.}
baidu.com
# '匹配到第一个 . 就停,删掉 www.'
[root@shell ~]# echo ${url#*.*.}
com
# 'w*.*. 匹配到第二个点,删掉 www.baidu.'
2)## 匹配 — 删除最长匹配(从前往后,贪婪)
[root@shell ~]# echo ${url##*.}
com
'贪婪匹配到最后一个点,只留下 com'
语法方向匹配方式记忆技巧
#从前往后==最短匹配==(懒惰)键盘上 # 在左,管左边
##从前往后==最长匹配==(贪婪)两个 # 就贪到底
%从后往前==最短匹配==(懒惰)键盘上 % 在右,管右边
%%从后往前==最长匹配==(贪婪)两个 % 就贪到底

从后往前删除#

Terminal window
[root@shell ~]# echo ${url}
www.baidu.com
1)% 匹配 — 从后往前删除最短匹配
[root@shell ~]# echo ${url%com}
www.baidu.
[root@shell ~]# echo ${url%.com}
www.baidu
[root@shell ~]# echo ${url%.*}
www.baidu
# '匹配到最后一个 . 前面的全部留下'
2)%% 匹配 — 从后往前删除最长匹配
[root@shell ~]# echo ${url%%.*}
www
# '贪婪从后往前,匹配到第一个 . 就全删了'

实战案例 — 去掉磁盘容量的单位 G

Terminal window
[root@shell ~]# df -h | awk 'NR==6'
/dev/sda3 48G 4.9G 43G 11% /
[root@shell ~]# df -h | awk 'NR==6{print $2}'
48G
[root@shell ~]# disk=`df -h | awk 'NR==6{print $2}'`
[root@shell ~]# echo $disk
48G
'${disk%G} — 从后面把 G 删掉,拿到纯数字'
[root@shell ~]# echo ${disk%G}
48
[root@shell ~]# [ ${disk%G} -gt 30 ]
-gt > '大于'
[root@shell ~]# echo $?
0
# '48 > 30,成立'
# 纯 awk
[root@shell ~]# df -h | awk -F '[ G]+' '{print $(NF-4)}'
48

子串替换#

Terminal window
[root@shell ~]# url=www.baidu.com
1)/ 替换 — 只替换第一个匹配
[root@shell ~]# echo ${url/w/W}
Www.baidu.com
单个 `/` 替换一次就停止
`//` 全局替换
[root@shell ~]# echo ${url/wW/W}
www.baidu.com
# 'wW 这个模式不存在,所以没替换'
[root@shell ~]# echo ${url/ww/W}
Ww.baidu.com
# '只替换了第一个 ww'
2)// 替换 — 替换所有匹配(全局替换)
[root@shell ~]# echo ${url//w/W}
WWW.baidu.com
# '所有的 w 都变成了 W'
3)替换域名 '百度' --> '京东'
[root@shell ~]# echo ${url/baidu/jd}
www.jd.com
语法含义
${变量/旧/新}替换第一个匹配
${变量//旧/新}替换所有匹配
${变量/#旧/新}匹配开头(必须是前缀)才替换
${变量/%旧/新}匹配结尾(必须是后缀)才替换
Terminal window
url="www.baidu.www.com"
# 1️⃣ 普通替换:只换第一个 w
echo ${url/w/W} # Www.baidu.www.com
# 2️⃣ 全局替换:所有 w 都换
echo ${url//w/W} # WWW.baidu.WWW.com
# 3️⃣ # 锚定开头:只有开头的 www 被替换
echo ${url/#www/W} # W.baidu.www.com
# 4️⃣ % 锚定结尾:只有结尾的 com 被替换
echo ${url/%com/COM} # www.baidu.www.COM
# ❌ # 不匹配开头时:什么都不发生
echo ${url/#baidu/BAIDU} # www.baidu.www.com(baidu不在开头,原样输出)

⚙️ 数值运算#

Shell 中常见的 6 种运算方式

方式整数小数效率推荐度
expr低(需 fork 子进程)⭐⭐
$(())==最高==(bash 内置)⭐⭐⭐⭐⭐
$[]高(bash 内置)⭐⭐⭐
let高(bash 内置)⭐⭐⭐
bc低(需 fork 子进程)⭐⭐⭐
awk低(需 fork 子进程)⭐⭐⭐

expr — 支持整数、不支持小数#

Terminal window
'expr 要求运算符两边必须有空格!'
[root@shell ~]# expr 1+1
1+1
# ❌ 没空格,当成字符串原样输出
[root@shell ~]# expr 1 + 1
2
'乘法需要用 \* 转义'
[root@shell ~]# expr 100 \* 10
1000
[root@shell ~]# expr 100 / 10
10
[root@shell ~]# expr 100 - 10
90

$(()) — 支持整数、效率最高#

Terminal window
'两个小括号' 推荐使用
[root@shell ~]# echo $((10+10))
20
[root@shell ~]# echo $((10-10))
0
[root@shell ~]# echo $((10*10))
100
[root@shell ~]# echo $((10/10))
1
[root@shell ~]# echo $((10%10))
0
# '% 是取余(取模)'

$[] — 不支持小数(老式语法)#

Terminal window
[root@shell ~]# echo $[10+10]
20
[root@shell ~]# echo $[10-10]
0
[root@shell ~]# echo $[10*10]
100
[root@shell ~]# echo $[10/10]
1
'$[] 是老式写法,推荐用 $(()) 替代'

let — 常用于自增/自减#

Tip

Shell(Bash)在进行算术运算时(包括 let(( ))expr),如果变量未被赋值或值为空,会自动将其当作 整数 0 处理

Terminal window
1)let i++ —-> 自增
[root@shell ~]# let i++
[root@shell ~]# echo $i
1
[root@shell ~]# let i++
[root@shell ~]# echo $i
2
2)let i=i+1
[root@shell ~]# let i=i+1
[root@shell ~]# echo $i
3
Important

📌 i++++i 的区别(有变量时不同):

Terminal window
[root@shell ~]# a=1
[root@shell ~]# b=1
[root@shell ~]# let c=a++ # 先赋值后运算
[root@shell ~]# let d=++b # 先运算后赋值
[root@shell ~]# echo $c
1
[root@shell ~]# echo $d
2
  • a++ → 先把 a 的值给 c,然后 a 自增
  • ++b → 先让 b 自增,再把结果给 d

实战 — 用 let 统计循环次数

[root@shell ~]# cat for.sh
#!/bin/bash
for i in I am lizhenya I am 18
do
let a++
done
echo 总共循环了 $a
[root@shell ~]# sh for.sh
总共循环了 6

bc — 支持整数和小数#

Terminal window
[root@shell ~]# echo 10+10 | bc
20
[root@shell ~]# echo 10-10 | bc
0
[root@shell ~]# echo 10*10 | bc
100
[root@shell ~]# echo 10/10 | bc
1
'bc 独有的优势:支持小数运算'
[root@shell ~]# echo 10+10.5 | bc
20.5
[root@shell ~]# echo 10.123+10.5 | bc
20.623
'小数除法'
[root@shell ~]# echo 10/3 | bc
3
[root@shell ~]# echo 10/2.5 | bc
4
[root@shell ~]# echo 10/2.3 | bc
4
# '默认不保留小数位'
'支持运算优先级'
[root@shell ~]# echo 10+2*2 | bc
14

awk BEGIN — 支持整数和小数#

Terminal window
[root@shell ~]# awk 'BEGIN{print 10*10}'
100
[root@shell ~]# awk 'BEGIN{print 10-10}'
0
[root@shell ~]# awk 'BEGIN{print 10/10}'
1
[root@shell ~]# awk 'BEGIN{print 10+10}'
20
[root@shell ~]# awk 'BEGIN{print 10+10*2}'
30
[root@shell ~]# awk 'BEGIN{print 10^22}'
10000000000000000000000
'awk 小数除法默认保留精度'
[root@shell ~]# awk 'BEGIN{print 10/3}'
3.33333
Tip

💡 选择建议

  • 整数运算 → $(()) 效率最高,bash 内置
  • 小数运算 → bcawk
  • 自增/统计 → let
  • ==运算中都支持变量==:$(($num1 * $num2))$[$num1 * $num2]expr $num1 + $num2

⚙️ 整数比较#

语法结构#

Terminal window
# 第一种: test
test 10 -eq 10
# 第二种: [ ] ✅ 最常用
[ 10 -eq 10 ]

✨比较符号#

运算符含义英文全称助记
-lt小于Less ThanLess Than
-gt大于Greater ThanGreater Than
-le小于等于Less or Equal
-ge大于等于Greater or Equal
-eq等于Equal=
-ne不等于Not Equal
Terminal window
'基础演示'
[root@shell ~]# test 10 -eq 10
[root@shell ~]# echo $?
0
[root@shell ~]# [ 10 -eq 10 ]
[root@shell ~]# echo $?
0
'搭配 && 和 ||'
[root@shell ~]# [ 10 -gt 5 ] && echo 成立 || echo 不成立
成立
[root@shell ~]# [ 10 -eq 5 ] && echo 成立 || echo 不成立
不成立
[root@shell ~]# [ 10 -lt 5 ] && echo 成立 || echo 不成立
不成立
[root@shell ~]# [ 10 -lt 10 ] && echo 成立 || echo 不成立
不成立
⚠️ '小于,不包含等于'
[root@shell ~]# [ 10 -ge 10 ] && echo 成立 || echo 不成立
成立 '≥'
[root@shell ~]# [ 10 -le 10 ] && echo 成立 || echo 不成立
成立 '≤'

支持变量#

Terminal window
[root@shell ~]# echo $num1
10
[root@shell ~]# echo $num2
10
[root@shell ~]# [ $num1 -eq $num2 ] && echo 成立 || echo 不成立
成立

支持命令#

Terminal window
[root@Rocky ~]# df -h | awk '/\/$/'
'先过滤出以根/结尾的行' --> 撬棍
/dev/mapper/rlm-root 16G 1.7G 15G 11% /
[root@shell ~]# df -h | awk -F "[ %]+" '/\/$/{print $(NF-1)}'
11
'获取根分区使用率(去掉 % 号)'
[root@shell ~]# [ `df -h | awk -F "[ %]+" '/\/$/{print $(NF-1)}'` -gt 10 ] && echo 成立 || echo 不成立
成立
'使用变量方式做比较 — 更清晰'
[root@shell ~]# disk=`df -h | awk -F "[ %]+" '/\/$/{print $(NF-1)}'`
[root@shell ~]# echo $disk
11
[root@shell ~]# [ $disk -gt 80 ] && echo 成立 || echo 不成立
不成立

灵活取值 — 子串删除配合整数比较#

Terminal window
'不加 awk -F 过滤,拿到的是 11% 带百分号'
[root@shell ~]# disk=`df -h | awk '/\/$/{print $(NF-1)}'`
[root@shell ~]# echo $disk
11%
[root@shell ~]# [ $disk -gt 10 ] && echo 成立 || echo 不成立
-bash: [: 11%: integer expression expected
不成立
# ❌ '带 % 不能直接做整数比较!'
'用 ${disk%\%} 去掉百分号'
[root@shell ~]# [ ${disk%\%} -gt 10 ] && echo 成立 || echo 不成立
成立
Tip

💡 ${disk%\%} — 用 \ 转义 %,表示从后面删除一个 % 字符

也可以用 ${disk%?} 删掉最后一个字符

Terminal window
[root@shell ~]# disk=$(df -h | awk '/\/$/{print $(NF-1)}')
[root@shell ~]# echo $disk
11%
[root@shell ~]# echo ${disk%?}
11

多整数比较 — -o-a#

⚠️ -o / -a 是过时语法,现代 Shell 脚本中不推荐使用

请用 || / &&[[ ]] 替代 ✅

含义❌ 旧写法(-o/-a✅ 推荐写法([[ ]]
OR[ A -o B ]`[[ A
AND[ A -a B ][[ A && B ]]
混合[ A -a B -o C ]`[[ A && B

实战案例#

🌰 案例 1 — 磁盘使用率告警

Tip

脚本逻辑流程

① 取主机名、IP、磁盘使用率 → ② 用 ${disk_use%\%} 去掉百分号 → ③ 整数比较判断 → ④ 大于阈值发告警,小于发正常通知

[root@shell ~]# cat disk.sh
#!/bin/bash
# 取值定义变量
HOST=`hostname`
IP=`hostname -I | awk '{print $1}'`
disk_use=`df -h | awk '/\/$/{print $(NF-1)}'`
# 比对判断
if [ ${disk_use%\%} -gt 10 ]
then
python3 weixin.py "ShiHao" "${IP}_$HOST: 磁盘告警" "当前磁盘使用率为$disk_use,请快速处理!"
else
python3 weixin.py "ShiHao" "${IP}_$HOST: 磁盘正常" "当前磁盘使用率为$disk_use,喝喝茶吧"
fi

🌰 案例 2 — 内存使用率超过 80% 告警

Terminal window
[root@shell ~]# free | awk 'NR==2{print $3/$2*100}'
20.3711
[root@shell ~]# t=`free | awk 'NR==2{print $3/$2*100}'`
[root@shell ~]# [ ${t%.*} -eq 20 ] && echo 成立
成立

📌 ${t%.*} — 从后面删除 . 及之后的内容,拿到整数部分


🌰 案例 3 — 负载平均值大于 1 则告警

Terminal window
[root@shell ~]# uptime
11:23:35 up 9:29, 2 users, load average: 0.18, 0.11, 0.09
num1=$(uptime | awk -F'[ ,]+' '{print $NF}')
num2=$(uptime | awk -F'[ ,]+' '{print $(NF-1)}')
nmu3=$(uptime | awk -F'[ ,]+' '{print $(NF-2)}')
⚠️ '只有bc 和 awk命令支持小数' --> 可以都乘100再比较

📦 文件判断#

语法结构与判断符号#

Terminal window
# 语法结构
test -f /etc/hosts
[ -f /etc/hosts ]
符号含义说明
-f==普通文件==存在则为真-f /etc/hosts
-d==目录==存在则为真-d /etc/
-e==存在==则为真(文件和目录都行)-e /etc/passwd
-r==可读==则为真-r /etc/hosts
-w==可写==则为真-w /etc/hosts
-x==可执行==则为真-x /etc/hosts
Terminal window
1)基础演示
[root@shell ~]# [ -f /etc/hosts ] && echo 存在 || echo 不存在
存在
[root@shell ~]# [ -f /etc/ ] && echo 存在 || echo 不存在
不存在
# '/etc/ 是目录,不是普通文件'
[root@shell ~]# [ -d /etc/ ] && echo 存在 || echo 不存在
存在
[root@shell ~]# [ -e /etc/ ] && echo 存在 || echo 不存在
存在
[root@shell ~]# [ -e /etc/passwd ] && echo 存在 || echo 不存在
存在
2)权限判断
[root@shell ~]# [ -r /etc/hosts ] && echo 存在 || echo 不存在
存在
[root@shell ~]# [ -w /etc/hosts ] && echo 存在 || echo 不存在
存在
[root@shell ~]# [ -x /etc/hosts ] && echo 存在 || echo 不存在
不存在
# '普通文件默认没有执行权限' --> 0644
[root@shell ~]# [ -x /etc/ ] && echo 存在 || echo 不存在
存在
# '目录默认有执行权限(x 对目录意味着可以 cd 进去)' --> 755

实战案例#

🌰 案例 1 — 文件存在则 source 执行

Terminal window
[root@shell ~]# unset name
[root@shell ~]# cat a.sh
name=gege
[root@shell ~]# echo $name
'🈳'
[root@shell ~]# cat test.sh
#!/bin/bash
[ -f /root/a.sh ] && . /root/a.sh
echo $name
[root@shell ~]# bash test.sh
gege
# 'a.sh 存在,source 执行后 $name 被导入当前脚本'

🌰 案例 2 — .bashrc 中的 -f 判断

.bashrc
[root@shell ~]# cat ~/.bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then # 如果 /etc/bashrc 存在则调用执行
. /etc/bashrc
fi
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

📌 这就是之前讲过的:~/.bashrc 里主动 source /etc/bashrc


🌰 案例 3 — 目录不存在则创建

Terminal window
[root@shell ~]# [ -d oldboy ] || mkdir oldboy
# 'oldboy 目录不存在 → 创建'

🌰 案例 4 — 支持 -o-a

Terminal window
[root@shell ~]# [ -f /etc/hosts -o -d hehe ] && echo 成立 || echo 不成立
成立
# '/etc/hosts 存在,-o 只要一个成立即可'
比起上面的方法,我更推荐下面这种方法
[root@shell ~]# [[ -f /etc/hosts || -d hehe ]] && echo 成立 || echo 不成立
成立
[root@shell ~]# [[ -f /etc/hosts && -d hehe ]] && echo 成立 || echo 不成立
不成立
# '/etc/hosts 存在但 hehe 目录不存在,&& 要求全部成立'

🔣 字符串判断#

语法结构#

Terminal window
test a = a
[ a = a ]
[ a != b ]

判断符号#

符号含义
=字符串相等
!=字符串不相等
-n字符串长度==不为 0==则成立
==n==ot empty(非空则为真)
-z字符串长度==为 0==则成立
==z==ero length(长度为 0 则为真)
Tip

-n-z 是相反的

  • -n-z 直接判断变量本身的值即可
    • 不需要使用 ${#name}
Terminal window
1)字符串相等/不相等
[root@shell ~]# [ root = root ] && echo 相等 || echo 不等于
相等
[root@shell ~]# [ aroot = root ] && echo 相等 || echo 不等于
不等于
2)判断字符串长度 -n 和 -z
[root@shell ~]# num=123
[root@shell ~]# [ -n $num ] && echo 成立 || echo 不成立
成立
# '-n 长度不为 0 → 成立'
[root@shell ~]# [ -z $num ] && echo 成立 || echo 不成立
不成立
# '-z 长度为 0 → 不成立'
Warning

⚠️ 重要提醒:务必加双引号

Terminal window
3)错误示范
[root@shell ~]# num=
[root@shell ~]# [ -n $num ] && echo 成立 || echo 不成立
成立 '我给了一个空,应该是不成立的 ❌'
[ -n $num ] → shell 展开为 [ -n ] → 永远成立(bug!)
[ -n "$num" ] → shell 展开为 [ -n "" ] → 正确判断空字符串 → 返回假 ✅
[root@shell ~]# [ -n "$num" ] && echo 成立 || echo 不成立
不成立
# 一定加引号
[root@shell ~]# [ -z "$num" ] && echo 成立 || echo 不成立
成立
# 长度为 0 → -z 成立'
Note

唯一不需要加引号的场景是纯数字算术比较且你确定变量==一定是合法整数==

  • 但即便如此,加引号也不会有任何副作用

💡 终极建议不要记”哪个可以省引号”,养成无条件加双引号的肌肉记忆

Terminal window
# ✅ 永远这样写
[ -n "$var" ]
[ -z "$var" ]
[ "$a" = "$b" ]
[ "$count" -gt 0 ]

实战案例#

🌰 案例 1 — 字符串比对(登录验证)

[root@shell ~]# cat name.sh
#!/bin/bash
echo -e "web01 web01@123.com\nweb02 web02@123.com\njiu jiu@123.com" > ./a.txt
read -p "请输入你的用户名: " name
num=`grep -w $name a.txt | wc -l`
# -w精确匹配 0/1
[ "$num" -ne 1 ] && echo 用户名错误请重新输入 && exit
read -s -p "请输入你的密码: " passwd
echo -e "\n"
[ "$passwd" != `grep -w $name a.txt | awk '{print $2}'` ] && echo 密码错误重新输入 && exit
echo 恭喜你登录成功
[root@shell ~]# cat ./a.txt
web01 web01@123.com
web02 web02@123.com
jiu jiu@123.com

🌰 案例 2 — 限制用户输入不能为空

[root@shell ~]# cat test.sh
#!/bin/bash
read -p "请输入你的姓名: " name
[ -z "$name" ] && echo "必须输入姓名" && exit
read -p "请输入你的年龄: " age
[ -z "$age" ] && echo "必须输入年龄" && exit
echo name=$name
echo age=$age

⚙️ 正则判断#

语法结构#

[[ 字符串 =~ 正则表达式 ]]
Important

正则判断必须用 [[ ]] ==双中括号==,不能用 [ ] 单中括号

=~ 是正则匹配操作符

基础用法#

Terminal window
'^ 匹配开头,$ 匹配结尾'
[root@shell ~]# [[ root =~ ^r ]]
[root@shell ~]# echo $?
0
# '以 r 开头 → 匹配成功'
[root@shell ~]# [[ root =~ t$ ]]
[root@shell ~]# echo $?
0
# '以 t 结尾 → 匹配成功'
[root@shell ~]# [[ root =~ o ]]
[root@shell ~]# echo $?
0
# '包含字母 o → 匹配成功'
⚠️ 不会自动加 ^(不强制开头匹配)
'包含判断'
[root@shell ~]# [[ $USER =~ t$ ]] && echo 成立 || echo 不成立
成立
[root@shell ~]# [[ root =~ s ]] && echo 成立 || echo 不成立
不成立

正则模式#

Terminal window
'[a-z] 匹配单个小写字母'
[root@shell ~]# [[ root =~ [a-z] ]] && echo 成立 || echo 不成立
成立
'^[a-z]+$ 匹配纯小写字母字符串'
# + 连续出现(一次及以上)
[root@shell ~]# [[ root =~ ^[a-z]+$ ]] && echo 成立 || echo 不成立
成立
[root@shell ~]# [[ 1root =~ ^[a-z]+$ ]] && echo 成立 || echo 不成立
不成立
# '1root、root1,中间有数字也不行'
'[a-Z] 匹配字母(含大小写)'
[root@shell ~]# [[ Aroot =~ ^[a-Z]+$ ]] && echo 成立 || echo 不成立
成立

实战案例#

  • 通过正则匹配控制传入的参数
Tip

正则中使用 “并且” 和 “或者”

Terminal window
&& # 并且 — [[ ]] 内部使用
|| # 或者 — [[ ]] 内部使用
[root@shell ~]# cat test.sh
#!/bin/bash
read -p "请输入你的姓名: " name
if [[ ! "$name" =~ ^[a-z]+$ ]] # 如果姓名不是连续的字符串则表达式成立
then # 成立则执行 then 后面的动作
echo "必须输入字符串"
exit
fi
read -p "请输入你的年龄: " age
if [[ ! "$age" =~ ^[0-9]+$ ]] # 如果年龄不是连续的数字则表达式成立
then # 成立则执行 then 后面的动作
echo "必须输入整数"
exit
fi
echo name=$name
echo age=$age

⚙️ if 条件判断#

单分支(一个条件一个结果)#

类似 [ 10 -eq 10 ] && echo 成立

Terminal window
if [ 条件表达式 ]
then
命令集合
fi
⚠️ 如果 then 写在 if 后面,'需要有;分号'
if [ 条件表达式 ];then
命令集合
fi
Tip

分号与换行];then 可以写在一行(中间必须有分号 ;

也可以把 then 单独写在下一行(此时不需要分号)

1)单分支各种写法
[root@shell ~]# cat if.sh
#!/bin/bash
if [ 10 -eq 10 ];then
echo 成立
fi
if [ 10 -eq 10 ]
then
echo 成立
fi
if [ -f /etc/hosts ]
then
echo 成立
fi
if [[ root =~ t$ ]]
then
echo 成立
fi
if [ 10 -eq 10 -o -f /etc/hosts ];then
# -o 单括号
echo 成立
fi
if [[ 10 = 10 && etc =~ e ]];then
# && 是双括号
echo 成立
fi
[root@shell ~]# bash test.sh
成立
成立
成立
成立
成立
成立
Note

📌 if 后面可以是 ==任何条件判断==:

  • 整数比较 [ 10 -eq 10 ]
  • 文件判断 [ -f /etc/hosts ]
  • 字符串判断 [ root = root ]
  • 正则判断 [[ root =~ t$ ]]
  • 多条件组合 [[ 10 = 10 && etc =~ e ]]

双分支(一个条件两个结果)#

类似 [ 10 -eq 10 ] && echo 成立 || echo 不成立

Terminal window
if [ 条件表达式成立 ];then
执行命令
else
执行命令
fi
[root@shell ~]# cat tesh.sh
#!/bin/bash
if [ -f $1 ];then
echo $1文件存在
else
echo $1文件不存在
fi
[root@shell ~]# bash test.sh /etc/hosts
/etc/hosts文件存在
[root@shell ~]# bash test.sh /blogggggggggg
/blogggggggggg文件不存在
[root@shell ~]# bash test.sh /etc
/etc文件不存在
# '/etc/ 是目录,-f 判断为假'

多分支(多个条件、多个结果)#

Terminal window
if [ 条件表达式1 ];then
命令
elif [ 条件表达式2 ];then
命令
elif [ 条件表达式3 ];then
命令
elif [ 条件表达式4 ];then
命令
else
命令
fi

实战案例#

🌰 案例 1 — 传入 2 个整数比较大小

[root@shell ~]# cat diff.sh
#!/bin/bash
read -p "输入两个整数空格间隔: " num1 num2
if [[ ! "$num1" =~ ^[0-9]+$ ]];then
echo 请输入整数
exit
fi
if [[ ! "$num2" =~ ^[0-9]+$ ]];then
echo 请输入整数
exit
fi
if [ $num1 -eq $num2 ]
then
echo "$num1 = $num2"
# 这里输出的是一整个字符串 --> 整体
elif [ $num1 -gt $num2 ]
then
echo "$num1 > $num2"
else
echo "$num1 < $num2"
fi

✨ 颜色输出#

颜色码颜色
\e[31m红色
\e[32m绿色
\e[33m黄色
\e[34m蓝色
\e[0m==重置颜色==

💡 核心使用公式

Terminal window
echo -e "\e[颜色码m 你的文字 \e[0m"
Note
  • 必须使用 echo -e,普通的 echo 不会解析 \e 转义符。
  • 文字后面务必加上 \e[0m 重置颜色,否则终端后续的所有输出都会变成该颜色
#!/bin/bash
echo -e "\e[34m====== 系统管理菜单 ======\e[0m"
echo -e "\e[32m(1)启动服务\e[0m"
echo -e "\e[33m(2)查看日志\e[0m"
echo -e "\e[31m(3)停止服务\e[0m"
echo -e "\e[34m=========================\e[0m"
read -p "请输入选项(1|2|3|4): " choice
if [ "$choice" == "1" ]; then
# 这里是字符串判断
echo -e "\e[32m✔ 服务启动成功\e[0m"
elif [ "$choice" -eq 2 ]; then
# 这里是数字比较(整数)
echo -e "\e[33m⚠ 正在读取日志...\e[0m"
elif [ $choice == "3" ]; then
echo -e "\e[31m✘ 服务已停止\e[0m"
else
echo -e "\e[31m✘ 无效选项\e[0m"
fi

📌 进阶小贴士(避免重复写颜色码)

在实际写脚本时,每次都写 \e[31m...\e[0m 会很繁琐,推荐在脚本开头定义变量:

Terminal window
RED='\e[31m'
GREEN='\e[32m'
YELLOW='\e[33m'
BLUE='\e[34m'
RESET='\e[0m'
# 使用时直接拼接,简洁且不易漏掉重置符
echo -e "${GREEN}操作成功${RESET}"
echo -e "${RED}错误:文件不存在${RESET}"

📌 小结#

Important

本章从变量子串出发,覆盖了 Shell 编程中最常用的变量操作和条件判断:

章节核心知识点关键语法
变量子串 — 长度统计字符串长度${#变量}
变量子串 — 删除从前往后/从后往前删除# ## % %%
变量子串 — 替换替换第一个/替换全部/ //
数值运算6 种运算方式$(())bc let
整数比较6 个比较符号-eq -ne -gt -ge -lt -le
文件判断6 个文件测试-f -d -e -r -w -x
字符串判断相等/不等/长度= != -n -z
正则判断[[ ]]=~ 匹配^ $ [a-z] +
if 判断单分支/双分支/多分支if-then-elif-else-fi

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

数值运算与if条件判断
https://www.kpyun.fun/posts/automation/shell/shell02/
作者
久棹
发布于
2026-06-24
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录