全部文章

编程语言

Shell 脚本入门

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

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

延伸阅读

参考链接