Shell - contains 判断字符是否存在于列表 && shell 逻辑判断踩坑

本文介绍了在Shell脚本中判断当前时间是否在特定时间数组内的实现,以及在实现过程中遇到的数组遍历、条件判断、正则表达式等常见错误和解决方案。通过示例代码详细解释了如何避免这些坑,帮助读者更好地理解和使用Shell脚本进行时间判断和数组操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.引言

使用 shell 实现时间判断逻辑时,需要判断对应 $hour 是否存在于目标 $ValidHour[*] 数组中,经过各种踩坑,最后用最简单的思路实现了 contains 操作。

二.实现

这里先整理下如何实现,后面会把介绍遇到的各种坑,有兴趣可以看看~

1.需求

任务执行时间为 6,12,18,脚本定时启动并判断是否要在该事件启动后续任务,类似于 crontab

hour=`date +%H`
validHour=('6' '12' '18')

2.shell - contains

function containsHour()
{
hour=$1
validHour=('6' '12' '18')
for _hour in ${validHour[*]}; do
if test $hour -eq $_hour; then
echo true
return
fi
done
echo false
}

# 判断存在
hour=`date +%H`
hourState=`containsHour $hour`

脚本添加 set -x 查看执行过程,思路很简单,通过 for 循环遍历判断字符,如果存在则 return true,否则遍历完毕并返回 false:

+ hour=10
++ containsHour 10
++ hour=10
++ validHour=('6' '12' '18')
++ for _hour in '${validHour[*]}'
++ test 10 -eq 6
++ for _hour in '${validHour[*]}'
++ test 10 -eq 12
++ for _hour in '${validHour[*]}'
++ test 10 -eq 18
++ echo false
+ hourState=false

三.踩坑

1.[] 与 [[]] 使用差别

[] : [] 表达式内支持字符串比较,但不支持数字直接 >,< 比较,需要使用转义符 \>,\< 才能判断数字大小,其次内部使用逻辑判断不能使用 &&,||,内部只支持 -a,-o 类似操作,不支持正则操作

正确操作✅ :

if [ 3 \> 2 -a 5 \> 4 ];then
echo true
else
echo false
fi
+ '[' 3 '>' 2 -a 5 '>' 4 ']'
+ echo true
true

错误操作1 ❎ :

-a 符号改为 &&,无法识别

+ '[' 3 '>' 2
cron.sh: line 71: [: missing `]'
+ echo false
false

错误操作2 ❎ :

>,< 未添加转义符,运算符当成 IO 操作符,运算失效

+ '[' 3 -a 5 ']'
+ echo true
true

[[]] : [[]] 为 [] 操作的扩充,常用于逻辑判断,由于 [] 特殊字符需要使用转义且条件过多时代码不易阅读,所以可以采用 [[]] 操作,其内部运算符不需要转义,对应的逻辑符号为 &&,||,内部不在支持 -a,-o 等操作,但支持正则操作 例如 [a-z].txt [1-9].sh

正确操作 ✅ :

if [[ 3 > 2 && 5 > 4 ]];then
echo true
else
echo false
+ [[ 3 > 2 ]]
+ [[ 5 > 4 ]]
+ echo true
true

错误操作 ❎ :

&& 换为 -a

cron.sh: line 71: syntax error in conditional expression
cron.sh: line 71: syntax error near `-a'
cron.sh: line 71: `if [[ 3 > 2 -a 5 > 4 ]];then'

正则操作 ✅ :

if [[ "a.txt" == *.txt ]];then
echo ture
else
echo false
fi
+ [[ a.txt == *.txt ]]
+ echo ture
ture

Tips: 如果 [[]] 换成 [] 或者将 *.txt 用 "*.txt" 包围则正则失效

2.字符相等判断

除了逻辑符号与 [] 的使用外,字符串判断也有问题

正确操作 ✅ :

a="a"
b="a"
if [ $a = $b ];then
echo ture
else
echo false
fi

可以使用 =,== 判断两个字符是否相等,除此之外数字也可以用该符号判断

错误操作 ❎ :

a="a"
b="a"
if [ $a -eq $b ];then
echo ture
else
echo false
fi
cron.sh: line 85: [: a: integer expression expected

-eq 用于数字比较,所以字符判断会一直返回 false

3.数组表示

for 循环遍历数组时,需要数组之间字符不需要 ',' 逗号隔开,否则会将逗号作为字符的一部分

正确操作 ✅ :

validHour=('6' '12' '18')

错误操作 ❎ :

validHour=('6', '12', '18')
for _hour in ${validHour[*]}; do
echo $_hour
6,
12,
18

6, 12, 变成了新的字符,所以判断 6 == 6, 12=12, 总是 false,让人怀疑人生

4.=~ 正则表达式判断

错误操作 ❎ :

判断元素是否存在时,有给出 =~ 的 demo,比较简洁:

hour='9'
validHour=('6' '12' '18')
if [[ "${validHour[@]}" =~ "$hour" ]];then
echo $hour Exist
fi

 “=~” 用于判断string和右边的正则表达式pattern是否匹配,如果需要做两个变量的包含关系可以使用,上述方法执行没有问题

+ hour=9
+ validHour=('6' '12' '18')
+ [[ 6 12 18 =~ 9 ]]
+ echo 9 Not Exist
9 Not Exist

但是当把 9 换成 1时,出现问题,1这个字符存在于数组变量中,即判断为 true,与 contains 的目标不符合,contains 需要全部相匹配才可有,因为这个问题半夜1点查问题  o(╥﹏╥)o,不过如果是要判断字符串的 contains 这个方法就可以使用了,因为他可以判断 "12" contains "1",只不过 Set contains 本场景不适用

+ hour=1
+ validHour=('6' '12' '18')
+ [[ 6 12 18 =~ 1 ]]
+ echo 1 Exist
1 Exist

正确操作 ✅ : 

如果想用这个简洁的方法,也可以增加判断 $hour -ge 6  $hour -le 18 控制 hour 的取值范围:

​hour='1'
validHour=('6' '12' '18')
if [[ "${validHour[@]}" =~ "$hour" ]] && [[ $hour -ge '6' ]] && [[ $hour -le '18' ]];then
echo $hour Exist
else
echo $hour Not Exist
fi
+ hour=1
+ validHour=('6' '12' '18')
+ validMinute=('0' '10' '20' '30' '40')
+ [[ 6 12 18 =~ 1 ]]
+ [[ 1 -ge 6 ]]
+ echo 1 Not Exist
1 Not Exist

正则操作 ⚠️ :

=~ 常用于正则匹配,例如最常见的判断变量是否为整数:

number=-15
# ps:正则表达式^表示起始,$表示结束,?表示0个或者1个
if [[ "$number" =~ ^-?[0-9]+$ ]]; then
echo "number is an integer."
else
echo "number is not an integer."
exit 1
fi
+ number=-15
+ [[ -15 =~ ^-?[0-9]+$ ]]
+ echo 'number is an integer.'
number is an integer.

四.总结

大半夜修 bug 顺便把最近遇到的相关 shell 坑总结在了一起,希望大家可以少走弯路 ^_^ ,对于本文中使用的 $hour,由于机器的异常原因可能并不会整点启动,所以还需要做规范化,可以参考hour 规范化 ~ 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值