进阶实战:Shell 脚本入门

Shell 脚本(Scripting)是 Linux 的精髓。当你发现自己在重复敲同一组命令超过三次时,就应该考虑写一个脚本来自动化它。


1. 脚本的仪式感:Shebang 与权限

每一个 Shell 脚本的第一行必须指定解释器。

#!/bin/bash
# 这是一个注释
echo "Hello, Linux!"
ℹ️ 如何执行?
  1. 赋予执行权: chmod +x my_script.sh
  2. 直接运行: ./my_script.sh
  3. 或指定解释器运行: bash my_script.sh

2. 基础交互与状态码

让脚本具备“对话”能力和“反馈”意识:

  • read: 获取用户输入。
  • printf: 格式化输出(比 echo 更强大)。
  • exit: 脚本退出的信号。0 代表成功,非 0 代表出错。
printf "请输入你的名字: "
read USERNAME
echo "欢迎,${USERNAME}!"
 
# 如果没有输入则报错退出
if [ -z "$USERNAME" ]; then
    echo "错误:名字不能为空!"
    exit 1
fi

3. 变量进阶:不仅是赋值

3.1 特殊变量列表

在脚本中,有一组“内置变量”可以让你轻松获取环境信息:

变量含义
$0脚本文件名本身
$1, $2...传入脚本的第 1, 2… 个参数
$#参数的总个数
$@所有参数的列表
$?最重要:上一条命令的退出状态码(0 为成功)

4. 逻辑控制:脚本的“大脑”

4.1 条件判断:[[ ]]

推荐使用双中括号 [[ ]],它比传统的 [ ] 更安全且支持正则。

# 检查文件是否存在且可写
if [[ -f "config.yaml" && -w "config.yaml" ]]; then
    echo "配置文件就绪"
fi

4.2 处理分支:case

当参数选项很多时,case 远比 if-else 清晰:

case "$1" in
    start)
        echo "启动服务..."
        ;;
    stop)
        echo "停止服务..."
        ;;
    *)
        echo "用法: $0 {start|stop}"
        ;;
esac

4.3 循环:forwhile

  • for: 遍历已知列表。
  • while: 只要条件成立就一直跑(常用于读取文件行)。

5. 工程化实践:写出“稳健”的脚本

新手写脚本是为了“跑通”,老手写脚本是为了“不出错”。

5.1 开启安全模式

在脚本开头加上这行,可以让脚本在出错或变量未定义时立即停止,避免引发连锁灾难:

set -euo pipefail

5.2 局部变量 local

在函数内部,务必使用 local 声明变量,防止污染全局环境。

5.3 静态分析工具:ShellCheck

强烈建议安装 ShellCheck。它能像语法检查器一样,指出你脚本中潜在的逻辑错误和不规范写法。


6. 自动化:定时任务与 Systemd

6.1 Cron:老牌定时任务

crontab -e 编辑任务列表:

  • 0 2 * * * /path/to/script.sh (每天凌晨 2 点执行)

6.2 Systemd Timer:现代方案

相比 Cron,Systemd Timer 提供了更精确的日志记录、依赖管理和容错处理。它由 .service.timer 两个文件组成。


7. 实战:系统体检与日志备份

#!/bin/bash
set -euo pipefail
 
# 配置
BACKUP_DIR="/tmp/system_logs"
LOG_FILE="/var/log/syslog"
DATE=$(date +%Y%m%d_%H%M%S)
 
# 确保目录存在
mkdir -p "$BACKUP_DIR"
 
echo "--- 系统体检开始 ---"
echo "磁盘占用:"
df -h | grep '^/dev/'
 
echo "备份日志中..."
tar -czf "${BACKUP_DIR}/log_${DATE}.tar.gz" "$LOG_FILE" 2>/dev/null
 
echo "完成!备份保存在:$BACKUP_DIR"

将此脚本加入定时任务,或者将其封装为 Systemd 服务以实现开机自启。


8. 结业练习

Navigation