在 Linux Bash 中编写脚本:面向初学者和系统管理员的完整指南
Bash 脚本编写是 Linux 用户、开发者或系统管理员所能掌握的最强大技能之一。无论您是管理单台服务器,还是在整个基础设施中编排复杂的自动化工作流,掌握 Bash 脚本编写都能显著减少手动工作量、最大程度降低人为错误,并充分释放 Linux 环境的潜力。
在本综合指南中,我们将带您了解编写 Bash 脚本所需的一切知识——从创建第一个文件,到使用变量、条件语句、循环、函数、参数和调试技术。全文包含大量可直接复制使用的实用示例。
什么是 Bash 脚本?
A Bash 脚本是一个纯文本文件,其中包含由 Bash shell(Bourne Again SHell)解释和执行的有序命令序列。Bash 是绝大多数 Linux 发行版的默认交互式 shell,因此具有普遍可用性和即时实用性。
您无需在终端中反复输入相同的命令序列,只需将它们写入脚本文件中,按需执行——或安排其自动运行。
Bash 脚本的常见使用场景
- 文件管理——批量复制、移动、重命名、归档和删除文件
- 系统管理——监控进程、管理用户、检查磁盘使用情况
- 软件自动化——安装软件包、配置服务、部署应用程序
- 备份与恢复——创建计划性、增量或完整系统备份
- 日志解析与报告——过滤和汇总日志数据以供分析
- 服务器配置——自动化新 VPS Hosting 或专用服务器环境的初始设置
前提条件
要学习本指南,您需要:
- 一个 Linux 系统(本地机器、VM 或远程服务器)
- 具有用户账户的终端访问权限(某些操作需要 root 或 sudo 权限)
- 对 Linux 命令行有基本了解
如果您在远程服务器上工作,AlexHost 的 VPS Hosting 方案提供完整的 root SSH 访问权限,非常适合在真实环境中练习和部署 Bash 脚本。
第一步:创建 Bash 脚本文件
打开终端,使用任意文本编辑器创建一个带有 .sh 扩展名的新文件。.sh 扩展名是一种广泛采用的约定,表示该文件是 shell 脚本,但解释器在技术上并不强制要求此扩展名。
nano myscript.sh您可以将 nano 替换为 vim、gedit、micro 或您偏好的任何其他编辑器。
第二步:添加 Shebang 行(#!)
每个 Bash 脚本的第一行必须是 shebang——一个特殊指令,告诉操作系统在执行文件时使用哪个解释器。
#!/bin/bash此行指示内核将脚本传递给 /bin/bash 执行,无论当前用户将哪个 shell 设置为默认值。请务必包含此行——省略 shebang 可能导致脚本在不同环境中行为不可预测。
> 提示:在某些现代系统上,您也可能看到 #!/usr/bin/env bash,这是一种更具可移植性的替代方案,通过 PATH 动态定位 Bash 二进制文件。
第三步:编写命令
在 shebang 之后,添加您希望脚本执行的命令。以下是一个简单示例,用于问候当前用户并显示有用的系统信息:
#!/bin/bash
# A simple script to greet the user and display system info
echo "Hello, $USER! Welcome back."
echo "Today's date and time: $(date)"
echo "Your current working directory: $(pwd)"
echo "System hostname: $(hostname)"关键元素说明
| 元素 | 描述 |
|---|---|
echo | 将文本或变量值打印到终端(标准输出) |
$USER | 保存当前用户名的内置环境变量 |
$(date) | 命令替换——执行 date 并将其输出内联插入 |
$(pwd) | 插入当前工作目录路径 |
$(hostname) | 插入系统主机名 |
# | 开始注释——被解释器忽略,用于文档说明 |
第四步:使脚本可执行
在直接运行脚本之前,您必须使用 chmod 命令授予其执行权限:
chmod +x myscript.sh这将为文件所有者设置执行位。要验证权限是否正确应用,请运行:
ls -l myscript.sh您应该看到类似 -rwxr-xr-x 的内容,其中 x 字符确认了执行权限。
第五步:运行脚本
使用以下语法从同一目录执行脚本:
./myscript.sh./ 前缀告诉 shell 在当前目录中查找文件,而不是搜索系统 PATH。您应该能在终端中看到直接打印的输出。
或者,您也可以使用解释器显式调用它:
bash myscript.sh
Bash 脚本中的变量
变量允许您在整个脚本中存储和重用数据。它们可以保存字符串、整数、文件路径或命令的输出。
定义和使用变量
#!/bin/bash
# Define variables
server_name="web-server-01"
max_connections=500
backup_dir="/var/backups"
# Use variables
echo "Server: $server_name"
echo "Max connections allowed: $max_connections"
echo "Backup directory: $backup_dir"
变量的重要规则
赋值时 = 号两侧不能有空格(name="value" 正确;name = "value" 不正确)
读取变量值时在变量名前加 $:$variable_name
在复杂字符串中使用花括号以提高清晰度:${variable_name}
变量名区分大小写:$Name 和 $name 是不同的变量
将命令输出捕获到变量中
#!/bin/bash
current_date=$(date +"%Y-%m-%d")
disk_usage=$(df -h / | awk 'NR==2 {print $5}')
echo "Date: $current_date"
echo "Root partition usage: $disk_usage"
Bash 中的条件语句
条件逻辑允许您的脚本根据评估条件做出决策并执行不同的代码路径。
基本 if / elif / else 结构
#!/bin/bash
echo "Enter a number between 1 and 100:"
read user_input
if [ "$user_input" -ge 1 ] && [ "$user_input" -le 50 ]; then
echo "Your number is in the lower half (1–50)."
elif [ "$user_input" -ge 51 ] && [ "$user_input" -le 100 ]; then
echo "Your number is in the upper half (51–100)."
else
echo "Your number is outside the valid range."
fi
常用比较运算符
运算符
含义
-eq
等于
-ne
不等于
-gt
大于
-lt
小于
-ge
大于或等于
-le
小于或等于
-z
字符串为空
-n
字符串不为空
-f
文件存在且为普通文件
-d
目录存在
检查文件是否存在
#!/bin/bash
config_file="/etc/nginx/nginx.conf"
if [ -f "$config_file" ]; then
echo "Configuration file found: $config_file"
else
echo "ERROR: Configuration file not found at $config_file"
exit 1
fi
Bash 脚本中的循环
循环允许您多次重复执行一组命令,可以在定义的范围内、项目列表上,或直到条件发生变化为止。
for 循环——遍历范围
#!/bin/bash
echo "Counting from 1 to 5:"
for i in {1..5}; do
echo " Iteration: $i"
done
for 循环——遍历项目列表
#!/bin/bash
servers=("web-01" "web-02" "db-01" "cache-01")
for server in "${servers[@]}"; do
echo "Pinging server: $server"
ping -c 1 "$server" &>/dev/null && echo " ✔ $server is reachable" || echo " ✘ $server is unreachable"
done
while 循环——在条件为真时持续运行
#!/bin/bash
counter=1
while [ $counter -le 5 ]; do
echo "Counter value: $counter"
counter=$((counter + 1))
done
echo "Loop complete."
until 循环——直到条件变为真时运行
#!/bin/bash
attempts=0
until [ $attempts -ge 3 ]; do
echo "Attempt $((attempts + 1))..."
attempts=$((attempts + 1))
done
echo "Maximum attempts reached."
Bash 脚本中的函数
函数让您能够封装可重用的逻辑块,使脚本更简洁、更模块化,也更易于维护——尤其是随着脚本复杂度的增加。
定义和调用函数
#!/bin/bash
# Define the function
greet_user() {
local username="$1"
echo "Hello, $username! Your session started at $(date +"%H:%M:%S")."
}
# Call the function with arguments
greet_user "Alice"
greet_user "Bob"
实用函数示例:检查服务状态
#!/bin/bash
check_service() {
local service_name="$1"
if systemctl is-active --quiet "$service_name"; then
echo "✔ $service_name is running."
else
echo "✘ $service_name is NOT running. Attempting to start..."
systemctl start "$service_name" && echo " Started successfully." || echo " Failed to start $service_name."
fi
}
check_service "nginx"
check_service "mysql"
check_service "ssh"
> 注意:local 关键字将变量的作用域限制在函数内部,防止在较大脚本中产生意外的副作用。
使用命令行参数
Bash 脚本在被调用时可以直接从命令行接受输入,从而实现灵活、可重用的脚本,根据提供的参数表现出不同的行为。
特殊参数变量
变量
描述
$0
脚本本身的名称
$1、$2、$3
第一、第二和第三个位置参数
$#
传递的参数总数
$@
所有参数(以列表形式)
$*
所有参数(以单个字符串形式)
$?
上一个执行命令的退出状态
示例:接受参数的脚本
#!/bin/bash
# Validate that exactly two arguments were provided
if [ $# -ne 2 ]; then
echo "Usage: $0 <source_directory> <destination_directory>"
exit 1
fi
source_dir="$1"
dest_dir="$2"
# Check that the source directory exists
if [ ! -d "$source_dir" ]; then
echo "ERROR: Source directory '$source_dir' does not exist."
exit 1
fi
echo "Copying files from '$source_dir' to '$dest_dir'..."
cp -r "$source_dir" "$dest_dir" && echo "Copy completed successfully." || echo "Copy failed."
运行方式如下:
./myscript.sh /var/www/html /var/backups/html_backup
退出码与错误处理
健壮的 Bash 脚本始终能优雅地处理错误。Linux 中的每个命令都会返回一个退出码:0 表示成功,任何非零值表示错误。
使用 exit 和 $?
#!/bin/bash
# Attempt to create a directory
mkdir /tmp/test_directory
if [ $? -eq 0 ]; then
echo "Directory created successfully."
else
echo "Failed to create directory."
exit 1
fi
使用 set -e 进行自动错误处理
在脚本顶部添加 set -e 会使脚本在任何命令返回非零退出码时立即退出——这是生产脚本的最佳实践:
#!/bin/bash
set -e # Exit on any error
set -u # Treat unset variables as errors
set -o pipefail # Catch errors in pipelines
echo "Starting deployment..."
cd /var/www/html
git pull origin main
systemctl reload nginx
echo "Deployment complete."
调试 Bash 脚本
即使是经验丰富的开发者也会编写出有 bug 的脚本。Bash 提供了内置工具,帮助您高效地追踪和修复问题。
方法一:使用 -x 标志运行(跟踪模式)
bash -x myscript.sh
这会在每个命令执行时将其打印到终端,前缀为 +,并显示所有展开变量的值。这是最常用的调试技术。
方法二:在脚本内添加 set -x
您可以为脚本的特定部分启用和禁用跟踪:
#!/bin/bash
echo "Normal execution..."
set -x # Enable tracing
cp /source/file /destination/
chmod 644 /destination/file
set +x # Disable tracing
echo "Tracing disabled again."
方法三:使用 echo 语句设置检查点
策略性地放置 echo 语句有助于验证变量值,并确认执行已到达脚本中的特定位置:
echo "DEBUG: backup_dir = $backup_dir"
echo "DEBUG: Reached checkpoint before rsync"
实际应用示例:自动化备份脚本
以下是一个完整的、可用于生产环境的 Bash 脚本,演示了本指南中涵盖的许多概念:
#!/bin/bash
set -euo pipefail
# ============================================================
# Automated Backup Script
# Description: Backs up a specified directory with a timestamp
# ============================================================
# Configuration
SOURCE_DIR="/var/www/html"
BACKUP_ROOT="/var/backups/web"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_NAME="backup_${TIMESTAMP}.tar.gz"
BACKUP_PATH="${BACKUP_ROOT}/${BACKUP_NAME}"
RETENTION_DAYS=7
LOG_FILE="/var/log/backup.log"
# Logging function
log() {
echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" | tee -a "$LOG_FILE"
}
# Validate source directory
if [ ! -d "$SOURCE_DIR" ]; then
log "ERROR: Source directory '$SOURCE_DIR' not found. Aborting."
exit 1
fi
# Create backup root if it doesn't exist
mkdir -p "$BACKUP_ROOT"
log "Starting backup of '$SOURCE_DIR'..."
# Create compressed archive
tar -czf "$BACKUP_PATH" -C "$(dirname "$SOURCE_DIR")" "$(basename "$SOURCE_DIR")"
log "Backup created: $BACKUP_PATH ($(du -sh "$BACKUP_PATH" | cut -f1))"
# Remove backups older than retention period
log "Removing backups older than ${RETENTION_DAYS} days..."
find "$BACKUP_ROOT" -name "backup_*.tar.gz" -mtime +"$RETENTION_DAYS" -delete
log "Backup process completed successfully."
这类脚本在任何生产服务器上都极具价值。如果您在 Dedicated Servers 或 VPS 上运行网站或应用程序,使用此类脚本结合 cron 任务自动化备份,可确保您的数据始终受到保护,无需手动干预。
使用 Cron 调度 Bash 脚本
要按计划自动运行 Bash 脚本,请使用 Linux 任务调度器 cron。使用以下命令编辑您的 crontab:
crontab -e
按以下格式添加一行:
# Run backup script every day at 2:00 AM
0 2 * * * /path/to/backup.sh >> /var/log/backup_cron.log 2>&1
Cron 语法:minute hour day-of-month month day-of-week command编写 Bash 脚本的最佳实践
遵循以下约定将使您的脚本更可靠、更易读且更易于维护:
- 始终在第一行包含 shebang(
#!/bin/bash) - 在生产脚本中使用
set -euo pipefail,以便尽早捕获错误 - 为变量加引号(
"$variable"),以防止单词分割和通配符展开问题 - 使用有意义的变量名——
backup_directory比bd更清晰 - 为代码添加注释——解释*为什么*,而不仅仅是*做什么*
- 验证输入——在继续之前检查所需的参数和文件是否存在
- 使用函数将复杂逻辑组织成可重用的命名块
- 在安全环境中测试,然后再在生产系统上运行脚本
- 在函数内使用
local变量,避免污染全局作用域 - 将重要操作记录到文件中,以便日后审计脚本行为
进一步提升 Bash 技能
掌握基础知识后,可以考虑探索以下高级主题:
- 使用
grep、sed和awk的正则表达式,实现强大的文本处理 - Here 文档(
heredoc),用于在脚本中嵌入多行字符串 - 进程替换和命名管道,用于复杂的数据管道
- 使用
trap进行信号处理,实现脚本的优雅终止 - 关联数组(Bash 4+),用于键值数据结构
- 脚本库——使用
source从共享文件中引用公共函数
如果您正在管理 Web 应用程序、数据库或电子邮件基础设施,Bash 脚本与 Shared Web Hosting(适合小型项目)或完全托管的 VPS with cPanel(适合需要图形界面与 shell 访问并存的环境)天然搭配。
对于运行数据密集型工作负载或机器学习管道的团队,Bash 脚本在 GPU Hosting 基础设施上编排作业同样极具价值——自动化模型训练运行、管理数据集以及处理环境设置。
结论
Bash 脚本编写是任何使用 Linux 的人不可或缺的技能——无论您是正在自动化第一个重复性任务的初学者,还是管理复杂服务器基础设施的高级系统管理员。本指南涵盖的概念——文件创建、变量、条件语句、循环、函数、参数处理、错误管理和调试——构成了编写可靠、生产级脚本所需的完整基础。
从小处着手:自动化您每天手动执行的一项任务。随着信心的增长,将这些构建块组合成越来越复杂的工具,节省大量工作时间,降低人为错误风险,并让您对系统拥有精确、可重复的控制。
要获得练习和部署 Bash 脚本的最佳环境,请探索 AlexHost 基于 Linux 的 VPS Hosting 方案——提供完整 root 访问权限、SSD 存储以及专为开发者和系统管理员设计的灵活配置。
