Shell 命令编写是 Linux 和 Unix 系统管理中不可或缺的技能,它通过将多个命令组合、使用控制流结构和函数,实现自动化任务处理,极大提升工作效率,Shell 脚本本质上是包含一系列 Shell 命令的文本文件,通过解释器逐行执行,能够完成文件操作、系统监控、数据处理等多种复杂任务,本文将从基础语法、高级特性、实战案例等方面,详细解析 Shell 命令编写的核心要点。

Shell 脚本基础与语法规范
编写 Shell 脚本首先需要选择解释器,常见的有 Bash(默认)、Sh、Zsh 等,脚本文件通常以 .sh 为后缀,首行需指定解释器,#!/bin/bash(称为 Shebang 行),脚本执行需赋予可读权限,可通过 chmod +x script.sh 实现,然后通过 ./script.sh 或 bash script.sh 运行。
变量定义与使用是 Shell 编程的基础,变量无需声明类型,直接通过 name="value" 定义,使用时需加 符号,如 echo $name,变量区分大小写,且默认以字符串形式存储,若需进行算术运算,需借助 expr、 或 let 命令,sum=$((a + b)),Shell 提供特殊变量,如 $0(脚本名)、$1-$9(位置参数)、(参数个数)、(上一条命令的退出状态)、(当前进程 ID)等,这些变量在参数传递和流程控制中至关重要。
输入输出重定向与管道是 Shell 命令的核心特性,输入重定向(<)将文件内容作为命令输入,如 sort < numbers.txt;输出重定向(>)覆盖文件内容,>> 追加内容到文件;错误重定向(2>)可将命令错误信息单独输出,ls /nonexistent 2> error.log,管道()则将前一个命令的输出作为后一个命令的输入,如 ps aux | grep nginx 可筛选包含 nginx 的进程。
控制流与条件判断
Shell 脚本通过条件判断和循环结构实现逻辑控制。if 语句是最基础的条件分支,格式为:

if [ condition ]; then
commands
elif [ condition ]; then
commands
else
commands
fi
条件判断需使用 test 命令或 [ ](注意 [ 与 ] 需空格分隔),常见条件包括:文件操作(-e 文件存在、-f 普通文件、-d 目录)、字符串比较( 等于、 不等于、-z 空字符串)、数值比较(-eq 等于、-ne 不等于、-gt 大于),判断文件是否存在:
if [ -e "/etc/passwd" ]; then
echo "文件存在"
fi
循环结构中,for 循环常用于遍历列表或文件,格式为:
for item in list; do
commands
done
遍历当前目录下的所有 .txt 文件:
for file in *.txt; do
echo "处理文件: $file"
done
while 循环则适用于条件驱动的循环,格式为:

while [ condition ]; do
commands
done
每隔 5 秒监控 CPU 使用率,直到超过 80%:
while [ $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1) -lt 80 ]; do
echo "CPU 使用率正常"
sleep 5
done
echo "CPU 使用率过高!"
函数与模块化设计
函数可将重复代码封装,提高脚本复用性,定义格式为:
function func_name() {
commands
return value # 返回值仅限 0-255,通常通过 $? 获取
}
调用函数直接写函数名,如 func_name,函数内部可通过 $1、2 等获取参数,通过 local 定义局部变量避免全局污染,封装一个日志函数:
log() {
local level=$1
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> /var/log/app.log
}
log "INFO" "服务启动成功"
log "ERROR" "连接数据库失败"
实战案例:自动化备份脚本
以下是一个自动备份指定目录并保留最近 7 天备份的脚本,综合运用了变量、条件判断、循环和函数:
#!/bin/bash
# 配置参数
SOURCE_DIR="/var/www/html"
BACKUP_DIR="/backup/website"
DATE=$(date +%Y%m%d)
RETENTION_DAYS=7
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 备份函数
backup() {
local backup_file="$BACKUP_DIR/backup_$DATE.tar.gz"
tar -czf "$backup_file" "$SOURCE_DIR" 2>/dev/null
if [ $? -eq 0 ]; then
log "INFO" "备份成功: $backup_file"
else
log "ERROR" "备份失败"
exit 1
fi
}
# 清理旧备份函数
cleanup_old_backups() {
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -exec rm {} \;
log "INFO" "已清理 $RETENTION_DAYS 天前的备份"
}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$BACKUP_DIR/backup.log"
}
# 主逻辑
backup
cleanup_old_backups
log "INFO" "备份任务完成"
脚本执行流程:首先创建备份目录,调用 backup 函数压缩源目录并记录日志,再通过 find 命令删除超过 7 天的旧备份,最后输出任务完成日志。
常见问题与调试技巧
编写 Shell 脚本时,常见错误包括语法错误(如缺少空格、括号不匹配)、逻辑错误(如条件判断失效)、命令执行失败(如文件路径错误),调试时可采用以下方法:
- 开启调试模式:在脚本首行后添加
set -x,会显示每条命令的执行过程; - 检查退出状态:通过 判断上一条命令是否成功,关键命令后可添加
|| exit 1; - 分步测试:将复杂脚本拆分为小段,逐段验证功能。
相关问答 FAQs
*问题 1:Shell 脚本中 、`$和$@的区别是什么?** 解答:$#表示脚本参数的个数,例如./script.sh arg1 arg2中$#为 2;$将所有参数视为一个整体(用空格分隔),如"$"输出为"arg1 arg2"$@将每个参数视为独立字符串,如"$@"输出为"arg1" "arg2",在循环中,for arg in "$@"会逐个处理参数,而for arg in "$*"` 会将所有参数作为一个字符串处理。
问题 2:如何在 Shell 脚本中实现多进程并行执行?
解答:可通过 & 将命令放入后台执行,结合 wait 等待所有进程完成。
task1() { sleep 3; echo "任务1完成"; }
task2() { sleep 2; echo "任务2完成"; }
task1 & # 任务1后台执行
task2 & # 任务2后台执行
wait # 等待所有后台任务完成
echo "所有任务完成"
此脚本会并行执行 task1 和 task2,总耗时约 3 秒(取最长任务时间),显著提升效率。
