Skip to content

12. Shell 脚本基础

12.1 第一个脚本

bash
#!/bin/bash
# 这是我的第一个 Shell 脚本
# 文件名:hello.sh

echo "Hello, Linux World!"
echo "当前时间: $(date)"
echo "当前用户: $(whoami)"
echo "主机名: $(hostname)"
bash
# 给脚本添加执行权限并运行
chmod +x hello.sh
./hello.sh
bash
$ ./hello.sh
Hello, Linux World!
当前时间: Sat Jun 20 10:30:00 CST 2026
当前用户: user
主机名: myserver

12.2 变量

bash
#!/bin/bash
# 变量示例

# 定义变量(等号两边不能有空格!)
NAME="Linux"
VERSION=6.5
TODAY=$(date +%Y-%m-%d)

# 使用变量
echo "系统: $NAME"
echo "版本: ${VERSION}"    # 花括号可选,用于消除歧义
echo "日期: $TODAY"

# 只读变量
readonly PI=3.14159

# 删除变量(只读变量无法删除)
unset NAME

# 特殊变量
echo "脚本名: $0"
echo "参数个数: $#"
echo "所有参数: $@"
echo "上一条命令的返回值: $?"
echo "当前进程 PID: $$"

# 字符串操作
STR="Hello World"
echo "长度: ${#STR}"         # 11
echo "子串: ${STR:0:5}"     # Hello
echo "替换: ${STR/World/Linux}"  # Hello Linux

12.3 条件判断

bash
#!/bin/bash
# 条件判断示例

# if-elif-else
AGE=25
if [ $AGE -lt 18 ]; then
    echo "未成年"
elif [ $AGE -ge 18 ] && [ $AGE -lt 60 ]; then
    echo "成年人"
else
    echo "老年人"
fi

# 文件测试
FILE="/etc/passwd"
if [ -f "$FILE" ]; then
    echo "$FILE 是普通文件"
fi
if [ -d "/home/user" ]; then
    echo "家目录存在"
fi
if [ -r "$FILE" ]; then
    echo "文件可读"
fi
if [ -x "/bin/ls" ]; then
    echo "ls 命令可执行"
fi

# 字符串比较
STR="hello"
if [ "$STR" = "hello" ]; then
    echo "字符串相等"
fi
if [ -z "$EMPTY" ]; then
    echo "变量为空"
fi

# 更现代的写法(双括号)
if [[ "$STR" == h* ]]; then
    echo "以 h 开头"
fi

# case 语句
case "$1" in
    start)
        echo "启动服务"
        ;;
    stop)
        echo "停止服务"
        ;;
    restart)
        echo "重启服务"
        ;;
    *)
        echo "用法: $0 {start|stop|restart}"
        exit 1
        ;;
esac

12.4 循环

bash
#!/bin/bash
# 循环示例

# for 循环 — 列表形式
for color in red green blue; do
    echo "颜色: $color"
done

# for 循环 — C 风格
for ((i=1; i<=5; i++)); do
    echo "数字: $i"
done

# for 循环 — 遍历文件
for file in /var/log/*.log; do
    echo "日志文件: $file"
done

# while 循环
COUNT=1
while [ $COUNT -le 5 ]; do
    echo "计数: $COUNT"
    ((COUNT++))
done

# while 读取文件每一行
while IFS= read -r line; do
    echo "行内容: $line"
done < /etc/hostname

# until 循环(条件为假时执行)
NUM=10
until [ $NUM -le 0 ]; do
    echo -n "$NUM "
    ((NUM--))
done
echo ""

# break 和 continue
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        continue   # 跳过5
    fi
    if [ $i -eq 8 ]; then
        break      # 到8就停
    fi
    echo $i
done
bash
$ ./loops.sh
颜色: red
颜色: green
颜色: blue
数字: 1
数字: 2
数字: 3
数字: 4
数字: 5
计数: 1
计数: 2
计数: 3
计数: 4
计数: 5
10 9 8 7 6 5 4 3 2 1
1
2
3
4
6
7

12.5 函数

bash
#!/bin/bash
# 函数示例

# 定义函数
greet() {
    local name=$1    # local 声明局部变量
    local time=$(date +%H)

    if [ $time -lt 12 ]; then
        echo "早上好,$name!"
    elif [ $time -lt 18 ]; then
        echo "下午好,$name!"
    else
        echo "晚上好,$name!"
    fi
    return 0
}

# 调用函数
greet "小明"
greet "小红"

# 带返回值的函数
add() {
    local sum=$(( $1 + $2 ))
    echo $sum    # 通过 echo 返回结果
}

result=$(add 3 5)
echo "3 + 5 = $result"

# 实用函数:检查命令是否存在
check_command() {
    if ! command -v "$1" &> /dev/null; then
        echo "错误: $1 未安装"
        return 1
    else
        echo "✓ $1 已安装: $(which $1)"
        return 0
    fi
}

check_command git
check_command docker
check_command nonexistent_cmd
bash
$ ./functions.sh
下午好,小明!
下午好,小红!
3 + 5 = 8
 git 已安装: /usr/bin/git
 docker 已安装: /usr/bin/docker
错误: nonexistent_cmd 未安装

12.6 实战脚本:系统信息报告

bash
#!/bin/bash
# sysinfo.sh — 系统信息报告脚本

echo "========================================="
echo "       系统信息报告 - $(date)"
echo "========================================="
echo ""

echo "--- 主机信息 ---"
echo "主机名: $(hostname)"
echo "内核版本: $(uname -r)"
echo "操作系统: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo "运行时间: $(uptime -p)"
echo ""

echo "--- CPU 信息 ---"
echo "型号: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo "核心数: $(nproc)"
echo "负载: $(cat /proc/loadavg | awk '{print $1, $2, $3}')"
echo ""

echo "--- 内存使用 ---"
free -h | grep -v Swap
echo ""

echo "--- 磁盘使用 ---"
df -hT | grep -v tmpfs | grep -v devtmpfs
echo ""

echo "--- 网络接口 ---"
ip -4 addr show | grep inet | grep -v 127.0.0.1 | awk '{print $2, $NF}'
echo ""

echo "--- Top 5 进程(内存) ---"
ps aux --sort=-%mem | awk 'NR<=6 {printf "%-10s %-8s %-6s %s\n", $1, $3"%", $4"%", $11}'
echo ""

echo "========================================="
echo "        报告生成完毕"
echo "========================================="
bash
$ chmod +x sysinfo.sh && ./sysinfo.sh
-----------------------------------------
       系统信息报告 - Sat Jun 20 10:30:00 CST 2026
-----------------------------------------

--- 主机信息 ---
主机名: myserver
内核版本: 5.15.0-91-generic
操作系统: Ubuntu 22.04.3 LTS
运行时间: up 15 hours, 23 minutes

--- CPU 信息 ---
型号: Intel(R) Core(TM) i7-12700H
核心数: 8
负载: 0.52 0.48 0.35

--- 内存使用 ---
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi       2.7Gi       156Mi       128Mi       999Mi

--- 磁盘使用 ---
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda1      ext4       50G   22G   26G  46% /
/dev/sda2      ext4      200G  156G   34G  83% /home

--- 网络接口 ---
192.168.1.100/24 eth0

--- Top 5 进程(内存) ---
root       2.3%     12.5%  /usr/sbin/mysqld
www-data   0.5%     8.2%   apache2
root       0.1%     3.1%   /usr/bin/dockerd
user       1.2%     2.8%   vim

-----------------------------------------
        报告生成完毕
-----------------------------------------