XYCOVO CONSOLE KURISU · WEB 渗透 / AI 辅助攻防 ONLINE
#006 · 2025-07-05✓ PASS

Shell 脚本编程

Shell 脚本编程完整教程:变量、条件判断、循环、函数、sed/awk 文本处理及自动化运维实战。
linuxshell脚本编程自动化AUTHOR: KURISU

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

← #005 Ansible 自动化运维…#007 路由策略… →