shell 和 bash 的区别
什么是 "shell"?
"shell"(中文常译为 "壳")是用户与操作系统内核(Kernel)之间的 "中间程序",它的核心作用是:
- 接收用户输入的命令(比如ls查看文件、cd切换目录);
- 将命令翻译成内核能理解的语言,让内核执行操作;
- 再将内核的执行结果返回给用户。
简单说,shell 就是 "用户操作内核的桥梁"。没有 shell,用户无法直接与内核交互(比如你在终端敲的所有命令,都需要 shell 来解析执行)。
"bash" 是什么?
"bash" 的全称是 "Bourne Again SHell"("再一次的 Bourne 壳"),它是众多 shell 实现中的一种,由 GNU 组织开发,诞生于 1989 年,目的是替代早期的 Bourne shell(sh,1979 年推出的第一个主流 shell)。
bash 的特点是:
- 兼容性强:完全兼容 Bourne shell(sh)的语法,老的 sh 脚本可以直接在 bash 中运行;
- 功能丰富:在 sh 的基础上增加了很多实用功能(比如数组、函数、更灵活的条件判断、命令补全等);
- 应用广泛:目前几乎所有 Linux 发行版(如 Ubuntu、CentOS)、macOS(默认 shell,不过最新版本可能切换为 zsh,但仍支持 bash)都将 bash 作为默认 shell,是最主流的 shell 实现。
区别
概念 | 本质 | 包含关系 | 典型应用 |
---|---|---|---|
shell | 命令行解释器的统称(类别) | 包含 bash、zsh、ksh 等 | 作为用户与内核的交互接口 |
bash | shell 的一种具体实现(实例)全称 Bourne Again SHell,shell 的主流实现 | 是 shell 的子集,最常用的一种 | 作为默认 shell,执行 shell 脚本 |
shell 脚本 | 用 shell 语法编写的自动化脚本 | 可由 bash、zsh 等多种 shell 执行 | 批量处理、自动化任务等 |
bash 脚本 | 用 bash 语法编写的.sh文件 | 自动化执行命令(批量处理、定时任务等) | 本质是 "命令的组合与逻辑控制" |
- 当我们说 "写 shell 脚本" 时,90% 以上的场景其实是 "写 bash 脚本"(因为 bash 最常用);而 "bash 编程" 就是用 bash 的语法规则来编写这类脚本,实现命令的自动化组合。
- zsh(macOS 新默认 shell),它们的基础语法和 bash 很像(因为都兼容 sh),但增加了各自的扩展功能 ------ 但核心逻辑仍属于 "shell 编程" 的范畴。
bash 基础编程的核心语法
核心语法模块
1. 变量操作(基础中的基础)
核心语法
- 赋值:变量名=值(等号两侧无空格,踩坑重灾区)
- 使用:变量名 或 {变量名}(加{}避免歧义,如${name}123)
- 只读变量:readonly 变量名(赋值后无法修改)
- 删除变量:unset 变量名(删除后变量值为空)
- 值为字符串:字符串可以用单引号,也可以用双引号,也可以不用引号
字符串特殊操作
需求 | 语法示例 | 结果(假设name="test") |
---|---|---|
取字符串长度 | ${#name} | 4 |
截取子串(从索引 0 开始) | ${name:1:2}(从 1 取 2 个) | es |
单引号(原样输出) | echo '${name}' | ${name}(不解析变量) |
双引号(解析变量) | echo "${name}" | test(解析变量值) |
-
示例
bashcount=1 # 正确赋值(无空格) name="test" # 双引号解析变量(若有空格需用双引号,如name="my test") echo ${count} # 输出1 echo ${#name}; # 4 字符串长度 echo ${name:1:2}; # es 从第1个字符开始,取2个字符 echo "------- ${name} -----------"; # ------- test ----------- readonly count # 设为只读,后续count=2会报错 unset name # 删除name,echo $name输出空 DATE1=`date`; DATE2=`date +%Y-%m-%d`; echo $DATE1; # 2025年10月17日 星期五 16时52分01秒 CST echo $DATE2; # 2025-10-17
2. 数组操作(批量数据处理)
核心语法
- 定义数组:数组名=(元素1 元素2 元素3)(元素用空格分隔)
- 取单个元素:${数组名[索引]}(索引从 0 开始)
- 取所有元素:{数组名\[\*\]} 或 {数组名[@]}(双引号下@更安全,元素含空格时不拆分)
- 数组长度:${#数组名[@]}(同字符串长度语法)
示例
bash
arr=(10 20 30 "hello bash") # 含空格元素需用双引号
echo ${arr[0]} # 输出10(第一个元素)
echo ${arr[*]} # 输出10 20 30 hello bash(所有元素)
echo ${arr[@]} # 输出10 20 30 hello bash(所有元素)
echo ${#arr[@]} # 输出4(数组长度)
# 遍历数组(推荐用@,兼容含空格元素)
for val in "${arr[@]}"; do
echo "元素:$val"
done
3. 脚本参数传递(运行时传值)
核心变量(运行脚本时用:./test.sh 参数1 参数2)
变量 | 含义 | 示例(./test.sh 10 20) |
---|---|---|
$0 | 脚本自身路径 / 文件名 | ./test.sh |
1−1-1−n | 第 1 到第 n 个参数 | 参数1 1=10,参数2 2=20 |
$# | 参数总数 | 2 |
$* | 所有参数(视为单个字符串) | 10 20 |
$@ | 所有参数(视为独立字符串) | 10 20(遍历更安全) |
示例
bash
# 脚本内容(test.sh)
echo "脚本名:$0"
echo "参数总数:$#"
echo "第一个参数:$1"
echo "所有参数:$@"
# 运行脚本:./test.sh 5 8
# 输出:
# 脚本名:./test.sh
# 参数总数:2
# 第一个参数:5
# 所有参数:5 8
4. 运算符
-
支持多种运算符,包括:
-
算数运算符
-
条件表达式要放在方括号之间,并且要有空格,例如:
bash# [ "\$a"=="\$b" ]是错误的,必须写成 [ "\$a" == "\$b" ] a=1; b=2 if [ "$a"=="$b" ]; then d="true"; else d="false"; fi echo $d # 输出 true(错误,虽然1≠2,但被当作非空字符串判断) # == 前后无空格 此时 bash 会将 "$a"=="$b" 整体视为一个单一字符串 # 判断逻辑变成:"这个字符串是否非空"(因为 [ ] 中单独的字符串会被判断为 "非空即真")
-
-
关系运算符
-
布尔运算符
-
逻辑运算符
-
字符串运算符
-
文件测试运算符
算术运算
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
- expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
- 乘号*需转义
- 两种更优的现代写法:
-
方式 1:$((...)) (推荐):无需转义,支持加减乘除取余,写法更简洁:
bash# 整数运算(推荐$((...))) total=$((3 + 2)) # 结果5,无需expr和转义 total1=$((5 * 2)) # 结果10,乘号不用加\ echo "3 + 2 = $total" # 输出:3 + 2 = 5 echo "5 * 2 = $total1" # 输出:5 * 2 = 10 # 浮点数运算(用bc)设置scale变量来控制小数点后的位数 # bc(Basic Calculator)是Linux中的一个命令行计算器工具,它支持任意精度的数值计算。 a=5 b=2 echo "scale=2; $a / $b" | bc # 输出2.50(保留2位小数)
-
方式 2:\[...\]:与`((...))` 类似,兼容性稍弱但写法简单:
bashtotal2=$[5 / 2] # 结果2(bash仅支持整数除法) echo "5 / 2 = $total2" # 输出:5 / 2 = 2
-
算术运算符
运算符 | 说明 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取余 |
= | 赋值 |
== | 相等,比较两个数字,相同返回true; |
!= | 不相等,比较两个数字,不相同返回true; |
bash
total=`expr 3 + 2`
echo "参数总和为:$total" # 5
total2=`expr 5 - 2`
echo "参数差为:$total2" # 3
total3=`expr 5 \* 2`
echo "参数积为:$total3" # 10
total4=`expr 5 / 2`
echo "参数商为:$total4" # 2
total5=`expr 5 % 2`
echo "参数余为:$total5" # 1
a=1
b=2
c=1
# 判断 a 是否等于 b,将结果(true/false)赋值给 d
if [ "$a" == "$b" ]; then
d="true"
else
d="false"
fi
echo "a == b ? $d" # 输出:a == b ? false
# 同理判断 a 和 c(相等)
if [ "$a" == "$c" ]; then
e="true"
else
e="false"
fi
echo "a == c ? $e" # 输出:a == c ? true
# 判断 a 是否不等于 b,将结果(true/false)赋值给 d
if [ "$a" != "$b" ]; then
d="true"
else
d="false"
fi
# 同理判断 a 和 c(是否不相等)
if [ "$a" != "$c" ]; then
e="true"
else
e="false"
fi
echo "a == b ? $d" # 输出:a == b ? true
echo "a == c ? $e" # 输出:a == c ? false
关系运算符
- 关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
- 六个关系运算符
运算符 | 说明 |
---|---|
-eq | 相等 |
-ne | 不相等 |
bash
# -eq
if [ $a -eq $c ]
then
echo " $a -eq $c: 检测两个数是否相等,相等返回 true"
else
echo "$a -eq $c: 检测两个数是否相等,不相等返回 false"
fi
# -ne
if [ $a -ne $b ]
then
echo "$a -ne $b: 检测两个数是否不相等,不相等返回 true"
else
echo "$a -ne $b : 检测两个数是否不相等,相等返回 false"
fi
# -gt
if [ $b -gt $a ]
then
echo "$b -gt $a: 检测左边的数是否大于右边的数,大于返回 true"
else
echo "$b -gt $a: 检测左边的数是否大于右边的数,不大于返回 false"
fi
# -lt
if [ $a -lt $b ]
then
echo "$a -lt $b: 检测左边的数是否小于右边的数,小于返回 true"
else
echo "$a -lt $b: 检测左边的数是否小于右边的数,不小于返回 false"
fi
# -ge
if [ $b -ge $a ]
then
echo "$b -ge $a: 检测左边的数是否大于等于右边的数,大于等于返回 true"
else
echo "$b -ge $a: 检测左边的数是否大于等于右边的数,不大于等于返回 false"
fi
# -le
if [ $a -le $b ]
then
echo "$a -le $b: 检测左边的数是否小于等于右边的数,小于等于返回 true"
else
echo "$a -le $b: 检测左边的数是否小于等于右边的数,不小于等于返回 false"
fi
布尔运算符
运算符 | 说明 |
---|---|
-a | 与运算,两个表达式都为 true 才会返回 true |
-o | 或运算,有一个表达式为 true 就返回 true |
! | 非运算,取反,表达式为 true 会返回 false |
bash
a=1
b=2
# 与运算符 -a
# 判断 a 是否大于等于 b 且 a 是否小于等于 b,将结果(true/false)赋值给 d
if [ $a -ge $b -a $a -le $b ]; then
d="true"
else
d="false"
fi
echo "a 是否大于等于 b 且 a 是否小于等于 b ? $d" # 输出:a 是否大于等于 b 且 a 是否小于等于 b ? false
# 或运算符 -o
# 判断 a 是否大于等于 b 或 a 是否小于等于 b,将结果(true/false)赋值给 d
if [ $a -ge $b -o $a -le $b ]; then
d="true"
else
d="false"
fi
echo "a 是否大于等于 b 或 a 是否小于等于 b ? $d" # 输出:a 是否大于等于 b 或 a 是否小于等于 b ? true
# 非运算符!
if [ ! $a -eq $b ]
then
echo "! $a -eq $b: 检测两个数是否不相等,不相等返回 true"
else
echo "! $a -eq $b: 检测两个数是否不相等,相等返回 false"
fi
逻辑运算符
运算符 | 作用(逻辑关系) |
---|---|
&& | 逻辑与(两者都为真) |
|| | 逻辑或(其中之一为真) |
bash
a=2;
b=6;
# 1. 现代写法([[ ]] + &&/||,推荐)
if [[ $a -gt 1 && $b -lt 8 ]]; then
echo "&&条件成立" # 会执行(2>1 且 6<8)
fi
if [[ $a -gt 1 || $b -lt 8 ]]; then
echo "||条件成立" # 会执行(2>1 且 6<8)
fi
# 2. 传统写法([ ] + -a/-o,需注意空格)
if [ $a -gt 1 -a $b -lt 8 ]; then # -a 表示"且"
echo "-a条件成立" # 会执行
fi
if [ $a -gt 1 -o $b -lt 8 ]; then # -a 表示"且"
echo "-0条件成立" # 会执行
fi