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 扩展阅读