Shell运算符

Shell 运算符详解(新手详细版)

本文档面向零基础新手,从“Shell 里有哪些运算、怎么写”讲起,详细说明算术运算、字符串操作、文件测试、比较运算、逻辑运算、位运算等,并配有大量示例。


一、Shell 里有哪些“运算”?

1.1 大致分类

  • 算术运算:加减乘除、取余、自增等(数字)
  • 字符串:拼接、长度、子串、比较、是否为空
  • 文件测试:是否存在、是否可读、是文件还是目录等
  • 比较运算:相等、不等、大于、小于(数字或字符串)
  • 逻辑运算:与、或、非(用于条件判断)
  • 位运算:按位与、或、异或等(少用,了解即可)

Shell 默认没有“浮点数”,算术一般是整数;需要小数可用 bc 等外部命令。


二、算术运算

2.1 用 $(( )) 做运算(推荐)

$(( 表达式 )) 会先算表达式,再把结果当成一个“值”参与命令。
表达式里变量可以不加 $(加了也行),运算符两侧可以有空格。

a=10
b=3
echo $(( a + b ))
# 13
echo $(( a - b ))
# 7
echo $(( a * b ))
# 30
echo $(( a / b ))
# 3(整除)
echo $(( a % b ))
# 1(取余)

运算符+-*/%(取余);** 表示乘方(部分 Shell 支持,Bash 支持)。

echo $(( 2 ** 10 ))
# 1024

2.2 自增、自减

$(( ))let 里可以用 ++

i=5
echo $(( i++ ))
# 5(先取值再加 1,i 变成 6)
echo $(( ++i ))
# 7(先加 1 再取值,i 变成 7)

j=10
echo $(( j-- ))
# 10
echo $(( --j ))
# 8

2.3 把结果存回变量

赋值把运算结果存起来:

sum=$(( 3 + 5 ))
echo $sum
# 8

count=0
count=$(( count + 1 ))
echo $count
# 1

2.4 let 命令(也可做算术)

let “表达式” 会计算表达式,并可用于给变量赋值;表达式里不要写 $,且通常用引号包起来。

let "x=5+3"
echo $x
# 8

let "y+=2"
# 等价于 y=$(( y+2 ))

日常更常用 $(( )),因为可以直接 echo $(( … ))x=$(( … ))

2.5 expr(老式,了解即可)

expr 是外部命令,用于简单算术和字符串长度等;运算符和数字之间要有空格,* 要转义。

expr 10 + 2
# 12
expr 10 * 2
# 20

新脚本建议用 $(( )),不必依赖 expr。

2.6 小数运算:用 bc

Shell 自身只做整数运算;要小数用 bc

echo "scale=2; 10/3" | bc
# 3.33

echo "3.14 + 2.5" | bc
# 5.64

scale=2 表示保留 2 位小数。

2.7 算术运算小结

运算符 含义 示例
+ – * / 加减乘除 $(( a + b ))
% 取余 $(( 10 % 3 )) → 1
** 乘方(Bash) $(( 2 ** 3 )) → 8
++ — 自增自减 $(( i++ ))
= += -= 等 赋值、复合赋值 在 (( )) 或 let 里用

三、字符串相关

3.1 字符串拼接(直接并排)

Shell 里字符串“拼接”就是把变量或字面量写在一起,中间可加空格(空格会保留在结果里)。

a="Hello"
b="World"
echo "$a $b"
# Hello World
echo "$a, $b"
# Hello, World

3.2 字符串长度:${#变量名}

s="hello"
echo ${#s}
# 5

3.3 子串:${变量:起始:长度}

  • 起始从 0 开始;可省略长度表示到末尾。
  • 若起始为负数,表示从末尾往前数(部分 Shell 支持)。
s="abcdef"
echo ${s:0:3}
# abc
echo ${s:2:2}
# cd
echo ${s:2}
# cdef(从下标 2 到末尾)

3.4 字符串“替换”:${var/旧/新}

  • ${var/旧/新}:第一个“旧”换成“新”。
  • ${var//旧/新}:所有“旧”换成“新”。
  • 不写“新”相当于删除。
path="/home/user/file.txt"
echo ${path/file/newfile}
# /home/user/newfile.txt
echo ${path////_}
# _home_user_file.txt(把所有 / 换成 _)

3.5 默认值、空值处理(和参数类似)

  • ${var:-默认}:var 未设或为空时用“默认”。
  • ${var:=默认}:未设或为空时给 var 赋值并展开。
  • ${var:?错误信息}:未设或为空时报错退出。
  • ${var:+有值时的替换}:有值才替换。
unset x
echo "${x:-未设置}"
# 未设置
echo "${x:=0}"
# 0(x 被设为 0)

3.6 字符串比较(在 [ ] 或 [[ ]] 里)

  • ===:相等;!=:不等。
  • -z “串”:长度为 0;-n “串”:长度非 0。
  • 建议变量加双引号[ "$a" = "$b" ]
a="hello"
b="hello"
if [ "$a" = "$b" ]; then
  echo "相等"
fi

if [ -z "$a" ]; then
  echo "为空"
else
  echo "非空"
fi

四、文件测试运算符

[ ][[ ]] 里用来判断“文件/路径”的状态;test 命令等价于 [ ]

4.1 存在与类型

写法 含义
-e 路径 存在(文件或目录)
-f 路径 存在且为普通文件
-d 路径 存在且为目录
-L 路径 存在且为符号链接
-b 路径 块设备
-c 路径 字符设备

4.2 权限与属性

写法 含义
-r 路径 可读
-w 路径 可写
-x 路径 可执行
-s 路径 存在且大小大于 0
-N 路径 自上次读后是否被修改(部分 Shell)

4.3 比较两个文件

写法 含义
文件1 -nt 文件2 文件1 比 文件2 新(newer than)
文件1 -ot 文件2 文件1 比 文件2 旧(older than)
文件1 -ef 文件2 同一设备同一 inode(硬链接或同一文件)

示例:

if [ -f "$1" ]; then
  echo "$1 是文件"
fi
if [ -d "/tmp" ]; then
  echo "/tmp 是目录"
fi
if [ -r "$file" ]; then
  echo "可读"
fi

五、数值比较(在 [ ] 里)

[ ] 中比较数字要用下面这些,不能=<>(会按字符串比较):

写法 含义
-eq 等于(equal)
-ne 不等于(not equal)
-gt 大于(greater than)
-ge 大于等于
-lt 小于(less than)
-le 小于等于

示例:

a=10
b=5
if [ "$a" -gt "$b" ]; then
  echo "a 大于 b"
fi
if [ "$a" -eq 10 ]; then
  echo "a 等于 10"
fi

注意:变量建议加引号;若变量为空,会变成 [ -gt 5 ] 等错误形式,所以先检查是否为空或数字更稳妥。


六、逻辑运算

6.1 在 [ ] 里:-a、-o、!

写法 含义
! 条件
条件1 -a 条件2 与(and)
条件1 -o 条件2 或(or)
if [ -f file.txt -a -r file.txt ]; then
  echo "存在且可读"
fi
if [ ! -d "/不存在的路径" ]; then
  echo "不是目录或不存在"
fi

6.2 用 &&、|| 连接命令(推荐)

命令1 && 命令2:命令1 成功(退出码 0)才执行命令2。
命令1 || 命令2:命令1 失败(非 0)才执行命令2。

[ -f file.txt ] && echo "存在"
mkdir backup || echo "创建失败"

[[ ]] 里可以直接写 &&||!

if [[ -f file.txt && -r file.txt ]]; then
  echo "存在且可读"
fi

6.3 逻辑与算术混合(在 (( )) 里)

(( )) 里可以做算术并当条件:非 0 为真,0 为假

a=5
if (( a > 0 && a < 10 )); then
  echo "a 在 0 到 10 之间"
fi

七、位运算(了解即可)

$(( )) 里支持按位运算:

运算符 含义
& 按位与
| 按位或
^ 按位异或
~ 按位取反
<> 左移、右移
echo $(( 5 & 3 ))
# 1
echo $(( 5 | 3 ))
# 7
echo $(( 5 ^ 3 ))
# 6
echo $(( 1 << 4 ))
# 16

八、赋值与复合赋值

8.1 普通赋值

name="张三"
count=0

注意= 两边不能有空格,否则会被当成命令和参数。

8.2 算术复合赋值(在 (( )) 里)

x=10
(( x += 5 ))
echo $x
# 15
(( x *= 2 ))
echo $x
# 30

8.3 字符串“追加”(拼接后赋值)

s="hello"
s="$s world"
echo $s
# hello world

九、[[ ]] 里的比较与正则

[[ ]] 中:

  • ==!= 可用于字符串比较;<> 按字典序(或当前 locale)。
  • =~ 表示“左边字符串”匹配“右边正则”。
s="hello world"
if [[ "$s" =~ ^hello ]]; then
  echo "以 hello 开头"
fi
if [[ "$s" == *world* ]]; then
  echo "包含 world(通配)"
fi

十、运算符优先级(简要)

算术 $(( )) 里:先乘除取余,后加减;可用 () 改变顺序。
逻辑:! 最高,再 &&,再 ||
写复杂式子时多用小括号提高可读性。

echo $(( (1+2) * 3 ))
# 9

十一、实用示例汇总

11.1 算术

# 求和
sum=$(( 10 + 20 ))
# 自增
i=0
i=$(( i + 1 ))
# 取余判断奇偶
if [ $(( n % 2 )) -eq 0 ]; then
  echo "偶数"
fi
# 小数
result=$(echo "scale=2; 10/3" | bc)

11.2 字符串

# 长度
len=${#str}
# 子串
sub=${str:0:5}
# 默认值
name=${1:-"访客"}
# 比较
[ "$a" = "$b" ]
[ -n "$a" ]

11.3 文件与数值比较

[ -f "$file" ]
[ -d "$dir" ]
[ "$count" -gt 0 ]
[ "$count" -le 100 ]

11.4 逻辑组合

[[ -f f && -r f ]]
[ "$x" -gt 0 -a "$x" -lt 10 ]
cmd1 && cmd2
cmd1 || cmd2

十二、常见坑与建议

  1. 赋值 = 两边不能有空格x=1 正确,x = 1 会报错。
  2. 数字比较用 -eq 等:在 [ ] 里用 -eq、-gt,不用 =>(会当字符串)。
  3. 变量加引号[ "$a" = "$b" ],避免空或含空格出错。
  4. 整数除法$(( 10/3 )) 是 3,要小数用 bc
  5. [[ ]] 与 [ ]:Bash 下推荐 [[ ]] 做条件,支持 &&||=~

十三、速查表

类型 写法示例
算术 $(( a+b ))$(( a**2 ))$(( i++ ))
字符串长度 ${#var}
子串 ${var:0:5}${var:2}
字符串替换 ${var/旧/新}${var//旧/新}
默认值 ${var:-默认}${var:=默认}
文件测试 -f-d-r-e
数值比较 -eq-ne-gt-lt-ge-le
字符串比较 =!=-z-n
逻辑 !-a-o&&||
位运算 $(( a & b ))$(( a << 1 ))

十四、小结

  • 算术:用 $(( ))let;只有整数,小数用 bc;注意 / 整除% 取余++/–
  • 字符串:拼接并排写;${#var} 长度;${var:起:长} 子串;${var/旧/新} 替换;比较用 =!=-z-n
  • 文件-f、-d、-r、-e 等在 [ ] 里用。
  • 数值比较[ ] 里用 -eq、-gt 等;逻辑-a、-o、!&&、||[[ ]] 里可用 =~ 正则。
  • 赋值:= 两边无空格;复合赋值在 (( )) 里用 += 等。

多写几段脚本练算术、字符串长度与子串、文件判断、数值与逻辑比较,再结合 Shell流程控制.mdShell传递参数.md 一起用,运算符就能用熟。


*文档以 Bash 为准;sh 或其它 Shell 在 *、(( )) 等上可能略有差异。

发表评论