全部文章

Shell 脚本入门

Bash 脚本基础语法、变量、条件判断、循环与实用脚本示例

目录 20 节

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

延伸阅读

参考链接

阅读建议
  • - 先读标题和摘要,再结合目录决定从哪个章节开始精读。
  • - 看到具体命令、配置或步骤时,尽量在自己的环境里同步验证。
  • - 如果你只是快速查资料,可先看目录和相关文档,再决定是否深入全文。
适合谁看
  • - 希望把零散经验整理成长期可复用工作流的人
  • - 想先建立认知,再决定是否深入实践的人
  • - 希望阅读时顺手建立自己的操作清单或收藏体系的人
执行前检查
  • - 先浏览标题、摘要和目录,带着问题阅读会更高效
  • - 顺手记录真正对你有用的命令、链接和注意事项,避免重复搜索
  • - 如果页面里提到相关文档,尽量一起打开对照,效果通常更完整
同类内容
← 上一篇Rust 入门