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 秒(取最长任务时间),显著提升效率。