Bash 脚本编写教程 / 01 - 入门与概览
01 - 入门与概览
1.1 什么是 Shell
Shell 是用户与操作系统内核(Kernel)之间的"壳层"——它接收用户输入的命令,交给内核执行,再把结果返回给用户。
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户 │────▶│ Shell │────▶│ Kernel │
│ (终端) │◀────│ (解释器) │◀────│ (内核) │
└──────────┘ └──────────┘ └──────────┘
1.2 Shell 的历史
| 年份 |
事件 |
说明 |
| 1971 |
Thompson Shell |
Ken Thompson 开发的第一个 Unix Shell |
| 1977 |
Bourne Shell (sh) |
Stephen Bourne 在贝尔实验室开发 |
| 1978 |
C Shell (csh) |
Bill Joy 在伯克利开发,引入 C 风格语法 |
| 1983 |
Korn Shell (ksh) |
David Korn 开发,兼容 sh 并增加新特性 |
| 1989 |
Bash 1.0 |
Brian Fox 为 GNU 项目开发,全称 Bourne Again SHell |
| 2004 |
Bash 3.0 |
引入关联数组、[[ =~ ]] 正则匹配 |
| 2009 |
Bash 4.0 |
支持关联数组(正式)、mapfile 内建命令 |
| 2019 |
Bash 5.0 |
新增 EPOCHSECONDS、EPOCHREALTIME 等变量 |
| 2022 |
Bash 5.2 |
增强参数展开、改进正则引擎 |
1.3 常见 Shell 类型
# 查看当前系统可用的 Shell
cat /etc/shells
# 查看当前使用的 Shell
echo $SHELL
echo $0
| Shell |
路径 |
特点 |
适用场景 |
| sh |
/bin/sh |
POSIX 标准,兼容性最好 |
系统脚本、跨平台脚本 |
| bash |
/bin/bash |
功能丰富,Linux 默认 |
日常脚本、系统管理 |
| zsh |
/bin/zsh |
交互体验优秀,Oh My Zsh |
交互式终端 |
| fish |
/usr/bin/fish |
开箱即用,语法友好 |
交互式终端(不兼容 POSIX) |
| dash |
/bin/dash |
轻量快速,POSIX 兼容 |
Debian/Ubuntu 系统脚本 |
| ksh |
/bin/ksh |
商业 Unix 标准 |
AIX、Solaris 系统 |
⚠️ 注意:在 Debian/Ubuntu 系统中,/bin/sh 指向 dash 而非 bash。编写跨平台脚本时需特别注意。
1.4 Bash 的适用场景
✅ 非常适合用 Bash 的场景
| 场景 |
示例 |
| 系统管理 |
用户批量创建、日志轮转、磁盘监控 |
| 文件批处理 |
批量重命名、格式转换、文件整理 |
| 自动化部署 |
代码拉取、构建、发布流水线 |
| 启动脚本 |
Docker ENTRYPOINT、systemd 服务 |
| 快速原型 |
一行命令(one-liner)快速验证想法 |
| 管道组合 |
将多个工具串联完成复杂任务 |
| 定时任务 |
cron 作业、监控报警 |
❌ 不适合用 Bash 的场景
| 场景 |
推荐替代 |
| 复杂数据处理 |
Python、Go |
| Web 服务 |
Python/Flask、Node.js |
| GUI 程序 |
Python/Tkinter、Rust |
| 数值计算 |
Python/NumPy、R |
| 超过 500 行的脚本 |
Python、Go |
| 需要强类型检查 |
Python、TypeScript |
1.5 Bash vs Python 全面对比
基础语法对比
| 特性 |
Bash |
Python |
| 变量赋值 |
name="hello" (等号两边无空格) |
name = "hello" |
| 字符串 |
"$name" (双引号展开) |
f"{name}" (f-string) |
| 条件判断 |
if [[ $a -gt 5 ]]; then ... fi |
if a > 5: ... |
| 循环 |
for i in {1..10}; do ... done |
for i in range(1, 11): ... |
| 函数 |
func() { echo "$1"; } |
def func(arg): print(arg) |
| 注释 |
# 单行注释 |
# 单行注释 |
| 数组 |
arr=(a b c) |
arr = ["a", "b", "c"] |
| 文件读取 |
while read line; do ... done < file |
for line in open("file"): |
执行速度对比
以遍历 100,000 次循环为例:
#!/bin/bash
# Bash: 循环 100000 次 —— 通常需要 1-3 秒
for ((i = 0; i < 100000; i++)); do
: # 空操作
done
#!/usr/bin/env python3
# Python: 循环 100000 次 —— 通常需要 0.01 秒
for i in range(100000):
pass
功能对比评分
| 维度 |
Bash |
Python |
说明 |
| 文件操作 |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
Bash 天生为文件系统操作设计 |
| 命令调用 |
⭐⭐⭐⭐⭐ |
⭐⭐⭐ |
Bash 直接执行,Python 需 subprocess |
| 文本处理 |
⭐⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
Bash 依赖外部工具,Python 有内置库 |
| 数据结构 |
⭐⭐ |
⭐⭐⭐⭐⭐ |
Bash 无字典嵌套、无对象 |
| 错误处理 |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
Bash 的错误处理机制较原始 |
| 可移植性 |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
Bash 版本差异大,Python 更一致 |
| 学习曲线 |
⭐⭐⭐⭐ |
⭐⭐⭐ |
Bash 入门容易但陷阱多 |
| 第三方库 |
⭐ |
⭐⭐⭐⭐⭐ |
Bash 基本无包管理生态 |
混合使用模式
实际项目中,Bash 和 Python 经常配合使用:
#!/bin/bash
# Bash 负责:环境准备、文件操作、调度
set -euo pipefail
WORK_DIR="/tmp/data_$(date +%s)"
mkdir -p "$WORK_DIR"
# 下载数据
curl -sL "https://api.example.com/data.json" -o "$WORK_DIR/raw.json"
# 交给 Python 处理复杂逻辑
python3 << 'PYTHON_SCRIPT'
import json, sys
with open("/tmp/data_*/raw.json") as f: # 简化示例
data = json.load(f)
processed = [item for item in data if item.get("status") == "active"]
print(json.dumps(processed, indent=2))
PYTHON_SCRIPT
# Bash 继续:清理、通知
rm -rf "$WORK_DIR"
echo "处理完成"
1.6 第一个 Bash 脚本
#!/bin/bash
# 文件名: hello.sh
# 描述: 第一个 Bash 脚本
echo "Hello, World!"
echo "当前时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "当前用户: $(whoami)"
echo "工作目录: $(pwd)"
# 运行方式一:赋予执行权限
chmod +x hello.sh
./hello.sh
# 运行方式二:通过 bash 解释器执行
bash hello.sh
# 运行方式三:source 执行(在当前 Shell 环境中运行)
source hello.sh
. hello.sh
1.7 如何学习本教程
| 阶段 |
章节 |
建议时间 |
| 入门 |
01-07 |
1-2 周,每天 1-2 章 |
| 进阶 |
08-15 |
2-3 周,配合实际项目练习 |
| 实战 |
16-20 |
2-3 周,在工作场景中应用 |
💡 学习建议:
- 每章代码示例亲手输入并运行
- 完成每章末尾的练习题
- 尝试用 Bash 解决工作中的实际问题
- 养成使用 ShellCheck 检查脚本的习惯
1.8 扩展阅读