#006 · 2025-07-05✓ PASS
Shell 脚本编程
Shell 脚本编程完整教程:变量、条件判断、循环、函数、sed/awk 文本处理及自动化运维实战。
Shell 脚本是 Linux 系统管理员的核心技能,掌握 Shell 编程意味着你可以自动化一切重复性工作。
一、脚本基础
创建第一个脚本
#!/bin/bash
# 这是我的第一个 Shell 脚本
echo "Hello, World!"
echo "当前时间: $(date)"
echo "当前用户: $(whoami)"
echo "工作目录: $(pwd)"
# 赋予执行权限
chmod +x script.sh
# 运行
./script.sh
# 或
bash script.sh
变量
#!/bin/bash
# 变量赋值(等号两边不能有空格)
name="Alice"
age=25
# 使用变量
echo "Name: $name"
echo "Age: ${age}"
# 只读变量
readonly PI=3.14
# 特殊变量
echo "脚本名: $0"
echo "参数1: $1"
echo "参数个数: $#"
echo "所有参数: $@"
echo "进程ID: $$"
echo "退出码: $?"
二、标准输入输出与重定向
# 标准文件描述符
# 0 - stdin 标准输入
# 1 - stdout 标准输出
# 2 - stderr 标准错误
# 输出重定向
ls -l > output.txt # 覆盖
ls -l >> output.txt # 追加
# 错误重定向
ls /nonexistent 2> error.log
# 合并输出
command > all.log 2>&1
# 输入重定向
read name < input.txt
wc -l < file.txt
# Here Document
cat > file.txt << EOF
这是第一行
这是第二行
这里是 $HOME
EOF
三、条件判断
test 命令 / [ ] 格式
# 数值比较
[ $a -eq $b ] # 等于
[ $a -ne $b ] # 不等于
[ $a -gt $b ] # 大于
[ $a -lt $b ] # 小于
[ $a -ge $b ] # 大于等于
[ $a -le $b ] # 小于等于
# 字符串比较
[ "$str1" = "$str2" ] # 相等
[ "$str1" != "$str2" ] # 不等
[ -z "$str" ] # 长度为零
[ -n "$str" ] # 长度不为零
# 文件测试
[ -f "$file" ] # 是否为普通文件
[ -d "$dir" ] # 是否为目录
[ -x "$file" ] # 是否可执行
[ -r "$file" ] # 是否可读
[ -w "$file" ] # 是否可写
[ -e "$path" ] # 是否存在
[ -s "$file" ] # 是否非空
# 逻辑运算
[ $a -gt 0 ] && [ $b -lt 100 ] # AND
[ $a -gt 0 ] || [ $b -lt 100 ] # OR
[ ! -f "$file" ] # NOT
if 语句
#!/bin/bash
score=85
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
elif [ $score -ge 60 ]; then
echo "及格"
else
echo "不及格"
fi
case 语句
#!/bin/bash
read -p "请输入 y/n: " choice
case $choice in
y|Y|yes|YES)
echo "你选择了是"
;;
n|N|no|NO)
echo "你选择了否"
;;
*)
echo "无效输入"
;;
esac
四、循环结构
for 循环
# 遍历列表
for fruit in apple banana orange; do
echo "水果: $fruit"
done
# C 风格
for ((i=1; i<=10; i++)); do
echo "第 $i 次"
done
# 遍历文件
for file in /etc/*.conf; do
echo "配置文件: $file"
done
while/until 循环
# while - 条件为真时执行
count=1
while [ $count -le 10 ]; do
echo "Count: $count"
((count++))
done
# until - 条件为假时循环
count=1
until [ $count -gt 10 ]; do
echo "Count: $count"
((count++))
done
# 读取文件
while IFS= read -r line; do
echo "$line"
done < /etc/passwd
五、函数
#!/bin/bash
# 定义函数
greet() {
local name=$1 # 局部变量
echo "Hello, $name!"
return 0
}
# 调用函数
greet "World"
echo "返回值: $?"
# 带返回值的函数
add() {
local result=$(($1 + $2))
echo $result # 通过 echo 返回结果
}
sum=$(add 5 3)
echo "5 + 3 = $sum"
六、数组
# 定义数组
fruits=("apple" "banana" "orange" "grape")
# 访问元素
echo ${fruits[0]} # 第一个
echo ${fruits[@]} # 所有元素
echo ${#fruits[@]} # 数组长度
# 遍历
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
# 添加
fruits+=("watermelon")
# 关联数组(bash 4+)
declare -A ages
ages["Alice"]=25
ages["Bob"]=30
echo ${ages["Alice"]}
七、sed 与 awk
sed(流编辑器)
# 替换(s/pattern/replacement/)
sed 's/old/new/g' file.txt # 替换所有
sed 's/old/new/2' file.txt # 替换第二个
sed -i 's/old/new/g' file.txt # 直接修改文件
# 删除
sed '/pattern/d' file.txt # 删除匹配行
sed '2,5d' file.txt # 删除 2-5 行
# 打印
sed -n '5p' file.txt # 打印第 5 行
sed -n '/pattern/p' file.txt # 打印匹配行
awk(文本处理)
# 基本格式
awk '{print $1, $3}' file.txt
# 条件过滤
awk '$3 > 100 {print $1, $3}' file.txt
# 使用分隔符
awk -F: '{print $1, $7}' /etc/passwd
# BEGIN/END 块
awk 'BEGIN {sum=0} {sum+=$1} END {print "Sum:", sum}' numbers.txt
# 统计 IP 访问次数
awk '{ip[$1]++} END {for (i in ip) print i, ip[i]}' access.log
八、实用脚本示例
系统监控脚本
#!/bin/bash
# sysmon.sh - 系统资源监控
echo "========== 系统监控 =========="
echo "主机名: $(hostname)"
echo "运行时间: $(uptime -p)"
echo ""
echo "CPU 使用率: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%"
echo "内存使用: $(free -h | awk '/^Mem:/ {print $3 "/" $2}')"
echo "磁盘使用:"
df -h | grep -E '^/dev/' | awk '{print " " $6 ": " $5 " (" $3 "/" $2 ")"}'
echo ""
echo "网络连接数: $(ss -tun | wc -l)"
echo "进程数: $(ps aux | wc -l)"
批量文件名重命名
#!/bin/bash
# 批量添加前缀
prefix="backup_"
for file in *.txt; do
mv "$file" "${prefix}${file}"
done