Shell 脚本入门
这页适合做“Bash 脚本从命令堆砌到可维护脚本”的起步说明。Shell 最常见的问题不是写不出来,而是脚本一旦开始处理参数、路径、错误和批量文件时,很容易因为细节没处理好而变脆。
什么时候适合用 Shell
Shell 脚本最适合下面几类任务:
- 批量执行系统命令
- 拼接现有 CLI 工具完成自动化
- 做部署、备份、巡检、日志处理
- 写短小的环境初始化脚本
如果逻辑开始变复杂,例如大量数据结构处理、复杂分支、跨平台 GUI 或长链路业务判断,可以考虑改用 Python、Go 或 PowerShell。
基础
#!/bin/bash
# 第一行指定解释器
echo "Hello World"
# 赋予执行权限
chmod +x script.sh
./script.sh
推荐脚本开头
多数生产或团队脚本,建议从这个头部开始:
#!/usr/bin/env bash
set -euo pipefail
它的含义可以简单理解为:
-e:命令失败立即退出-u:未定义变量报错pipefail:管道中任意一步失败都能被捕获
变量
# 赋值(等号两边不能有空格)
name="Domi"
count=42
# 使用
echo "Hello $name"
echo "Count is ${count}"
# 命令结果赋值
today=$(date +%Y-%m-%d)
files=$(ls | wc -l)
# 只读
readonly PI=3.14
# 特殊变量
$0 # 脚本名
$1 # 第一个参数
$# # 参数个数
$@ # 所有参数
$? # 上一个命令的退出码
$$ # 当前进程 PID
条件判断
# if
if [ "$name" = "Domi" ]; then
echo "Hi Domi"
elif [ "$name" = "Admin" ]; then
echo "Hi Admin"
else
echo "Who are you?"
fi
# 数字比较
if [ "$count" -gt 10 ]; then
echo "Greater than 10"
fi
# -eq 等于 -ne 不等于 -gt 大于 -lt 小于 -ge 大于等于 -le 小于等于
# 文件判断
if [ -f "file.txt" ]; then echo "文件存在"; fi
if [ -d "dir" ]; then echo "目录存在"; fi
if [ -z "$var" ]; then echo "变量为空"; fi
if [ -n "$var" ]; then echo "变量非空"; fi
# 逻辑运算
if [ "$a" -gt 0 ] && [ "$b" -gt 0 ]; then
echo "Both positive"
fi
循环
# for
for i in 1 2 3 4 5; do
echo $i
done
for file in *.txt; do
echo "Processing $file"
done
for i in $(seq 1 10); do
echo $i
done
# C 风格
for ((i=0; i<10; i++)); do
echo $i
done
# while
count=0
while [ $count -lt 5 ]; do
echo $count
count=$((count + 1))
done
# 读取文件每一行
while IFS= read -r line; do
echo "$line"
done < file.txt
函数
greet() {
local name=$1 # local 变量
echo "Hello $name"
return 0
}
greet "Domi"
result=$(greet "World")
字符串操作
str="Hello World"
# 长度
echo ${#str} # 11
# 截取
echo ${str:0:5} # Hello
echo ${str:6} # World
# 替换
echo ${str/World/Bash} # Hello Bash
# 默认值
echo ${var:-"default"} # 变量为空时用默认值
实用脚本
备份脚本
#!/bin/bash
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
SOURCE="/var/www"
tar -czf "$BACKUP_DIR/www_$DATE.tar.gz" "$SOURCE"
# 保留最近 7 天
find "$BACKUP_DIR" -name "www_*.tar.gz" -mtime +7 -delete
echo "Backup completed: www_$DATE.tar.gz"
批量重命名
#!/bin/bash
for file in *.JPG; do
mv "$file" "${file%.JPG}.jpg"
done
健康检查
#!/bin/bash
URL="https://example.com"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$STATUS" != "200" ]; then
echo "⚠️ $URL returned $STATUS"
# 发送告警...
fi
调试
# 显示执行的每一行
bash -x script.sh
# 在脚本中开启
set -x # 开启调试
set +x # 关闭调试
# 遇到错误立即退出
set -e
# 推荐的脚本开头
set -euo pipefail
常见坑
变量没加引号
这是 Shell 里最容易出问题的一类错误。路径里一旦有空格,没加引号就很容易炸。
rm "$file"
cp "$source" "$target"
用 for file in $(ls ...)
这会在遇到空格、换行、特殊字符时出问题。遍历文件时,优先直接使用 glob 或 find + while read。
把脚本写成大段命令堆
一旦脚本超过几十行,就建议开始:
- 拆函数
- 打日志
- 明确参数和退出码
- 在关键步骤前做存在性检查
编写建议
- 给脚本加
--help或最少的参数说明 - 对危险操作先打印目标路径
- 删除、覆盖、重启服务这类动作前,尽量做显式确认
- 提交前跑一遍 ShellCheck
延伸阅读
参考链接
- Bash 手册 — 官方文档
- ShellCheck — 在线 Lint
- explainshell — 命令解释