Shell中运算操作和常见错误解决

1,885 阅读3分钟

运算操作

shell脚本在各种linux操作系统中触手可及,利用它执行特定任务十分强大且便捷,通用性强,反而是在处理各种看似简单的四则运算等操作上让人眉头一皱,整理记录shell中的运算类操作如下。

四则运算

不经常写脚本的同学,遇到的第一个坎就是这个——shell脚本中不能直接做加减乘除(报错command not found):

可以在线Shell工具尝试undefinedBash 在线工具 | 菜鸟工具

#!/bin/bash
echo '加法错误示范'
1+1
# 执行结果
加法错误示范
script.sh: line 3: 1+1: command not found
Exited with error status 127

它把1+1当做一条命令去解析,自然找不到。正确写法,举常用的两种:

  • 双括号包括
  • expr表达式运算
#!/bin/bash
echo '双括号(())--此处不用空格'
((a=1+1))
echo $a#!/bin/bash
echo 'expr 必须带空格'
expr 1 + 1

运行结果:

双括号(())--此处不用空格
2
expr 必须带空格
2

逻辑运算

这里只说3种逻辑运算符:与(AND),或(OR),非(NOT):

在shell中,”与”的运算符为”-a”,”与”的逻辑运算符也可以用”&&”表示。

在shell中,”或”的运算符为”-o”,”或”的逻辑运算符也可以用”||”表示。

  • !(非) &&(与) ||(或)中“!”优先级最高。
  • 逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算术运算符。
#!/bin/bash
a=1
b=98
((c=$a+$b))
if [ $a > 0 ] && [ $b > 0 ]
then
echo "两个正数"
fiif [ $c -ne 100 ];then echo "没有满分";fi

运行结果:

两个正数
没有满分

逻辑组合更多细节参考:shell中的逻辑运算/布尔运算/短路与/短路或-博客

更多逻辑比较的写法,如-f 判断文件是否存在,-d判断目录是否存在,可参考Linux shell 逻辑运算符、逻辑表达式详解

使用场景:if条件的组合

列表求和

前面已经解决了基础的加减乘除运算的问题,有一个更常见的需求是要把获取到的数值进行求和:

#!/bin/bash
i=1
sum=0
while [ $i -le 100 ]
do
  let sum=sum+$i
  let i+=1
doneecho $sum
# 结果是5050(当然啦,高斯会告诉你更快的算法)

使用场景:一般是配合从文件中匹配检索到特定的数值(grep+awk),然后进行循环求和

小Case集合

1. shell脚本参数表示(最基础)

写法含义
$#指的是参数个数
$0指的是脚本本身的名字,如终端输入./foo_config. sh hello world ,$0值就是xxxx_config. sh
$1指的是传递给该shell脚本的第一个参数,$1值就是hello
$2指的是传递给该shell脚本的第二个参数,$2值就是world
$$指的是脚本运行的当前进程ID号
$?指的是显示最后命令的退出状态,0表示没有错误,其他表示有错误

基本功:使用#判断脚本参数、函数参数是否为空,使用?判断最后命令执行是否成功进行相应操作,如错误重试,错误提示。

#!/bin/bash
function getNumber(){
echo $#
}
​
getNumber who am i
echo $?
# 结果是3和0

2. curl只获取http响应码

当你需要对某个请求的成功与否做处理时你就需要本知识。

curl -s -w "%{http_code}" 'your_http_url' -o /dev/null
# 用http_code来判断请求的响应情况,200,404等等

3. 实现try catch

{ } && { }这种情况下,只有左边成功执行了,右边的shell才会执行。

{ } || { }这种情况,左边shell脚本执行失败,右边才会执行,刚好可以实现try catch的功能。

{ # try     
    command1     
    #save your output 
} || { 
    # catch    
    # save log for exception
}

这只是利用了逻辑与或的原理达成此类效果。要注意的是这个写法需要在shell脚本中使用,不能直接在控制台执行,否则大括号也会被当做命令解析而报错。

常见错误处理

unary operator expected

xxx.sh: line 133: [: -eq: unary operator expected
# 例如第133行语句是 if [ $1 -eq 1 ],但调用时没有传参数值

这种错误在我们多次进行获多次调用变量比较时很容易遇到:作者在编写一个服务器环境处理脚本的时候,已一个变量来判断是用户主动调用还是被动使用,在被动使用时传递了变量0,主动调用时未传递,就有此报错。

原因:如果变量$1值为空,语句就成了 [ -eq 1 ] ,显然 [ 和 "1" 不相等并且缺少前面的 [ 符号,所以报了这样的错误。当然不总是出错,如果$1值不为空,语句就正常运行了,所以这样的错误是条件触发的比较隐蔽。

“unary operator expected”这个报错翻译过来是“期望一元运算符”,原意是说这里应该是一个一元操作符,如逻辑非,但并不是我们程序的本意。

解决办法(任选其一):

a. 保证传参$1不为空,赋予其默认值即可。

b. 将语句改写为if [[ $1 -eq 1 ]]

a方案是逻辑层面的规避,要求自检代码,保证没有空值比较,类似于java等的非null判定

b方案是语法层面规避

syntax error: unexpected end of file

一般是少写了done或者fi,分别用于doif的配对结束。

错误写法:

#!/bin/bash
a=1
b=98
((c=$a+$b))
if [ $a > 0 ] && [ $b > 0 ]
then
echo "两个正数"
## 错误示范,请勿模仿!

报错:

script.sh: line 8: syntax error: unexpected end of file
Exited with error status 2

line x: [: missing `]'

常见于if语句中由于缺少空格而导致的错误。if后面的方括号表达式前后记得加空格。

line x: [: too many arguments

#!/bin/bash
foo="hello world"
if [ $foo = "hi" ]
then
echo "打招呼"
fi

运行结果是:script.sh: line 3: [: too many arguments

$foo包含空格时,就出现上述的错误了,应当用双引号将变量括起来。

#!/bin/bash
foo="hello world"
if [ "$foo" = "hi" ]
then
echo "打招呼"
else
echo "其他"
fi

变量赋值时等号两侧不能加空格

#!/bin/bash
a=5
b = 5
if [ $a = $b ]
then
echo "a和b相等"
fi

运行结果:

script.sh: line 3: b: command not found
script.sh: line 4: [: 5: unary operator expected