> Shell脚本编程入门:自动化你的日常运维

为什么要学Shell脚本

如果你发现自己经常重复执行一组命令,那就该写脚本了。比如我每次部署代码要执行5个命令——拉代码、编译、停服务、复制文件、起服务。写成脚本后一键搞定,效率提升不止一点。

Shell脚本不需要安装任何东西,Linux自带Bash就能跑。

第一个Shell脚本

1
$ vim hello.sh
1
2
3
4
5
6
#!/bin/bash
# 第一个Shell脚本
echo "Hello, World!"
echo "当前时间: $(date)"
echo "当前用户: $(whoami)"
echo "当前目录: $(pwd)"

运行:

1
2
3
4
5
6
$ chmod +x hello.sh
$ ./hello.sh
Hello, World!
当前时间: Mon Jan 14 10:00:00 UTC 2026
当前用户: root
当前目录: /root

第一行#!/bin/bash叫shebang,告诉系统用哪个解释器来执行脚本。

变量

基本变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash

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

echo "系统: $NAME"
echo "版本: $VERSION"
echo "日期: $TODAY"

# 只读变量
readonly PI=3.14
# PI=3.15  # 这行会报错

特殊变量

变量含义示例
$0脚本名./deploy.sh
$1-$9位置参数第1-9个参数
$#参数个数3
$@所有参数arg1 arg2 arg3
$?上个命令退出码0表示成功
$$当前进程PID12345
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash
echo "脚本名: $0"
echo "参数个数: $#"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数: $@"

# 运行:./test.sh hello world
# 输出:
# 脚本名: ./test.sh
# 参数个数: 2
# 第一个参数: hello
# 第二个参数: world
# 所有参数: hello world

条件判断

if语句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash

# 检查文件是否存在
if [ -f "/etc/nginx/nginx.conf" ]; then
    echo "Nginx配置文件存在"
else
    echo "Nginx配置文件不存在,可能未安装"
fi

# 检查服务是否运行
if systemctl is-active --quiet nginx; then
    echo "Nginx正在运行"
else
    echo "Nginx未运行,正在启动..."
    sudo systemctl start nginx
fi

常用测试条件

条件含义示例
-f file文件存在且是普通文件[ -f /etc/passwd ]
-d dir目录存在[ -d /var/www ]
-z str字符串为空[ -z "$VAR" ]
-n str字符串非空[ -n "$VAR" ]
-eq数字相等[ $a -eq $b ]
-gt大于[ $a -gt 10 ]
-lt小于[ $a -lt 100 ]
=字符串相等[ "$str" = "hello" ]

case语句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

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

循环

for循环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# 遍历列表
for server in web1 web2 web3; do
    echo "正在检查 $server ..."
    ping -c 1 $server > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "  $server 在线"
    else
        echo "  $server 离线!"
    fi
done

# 遍历数字范围
for i in {1..5}; do
    echo "第 $i 次循环"
done

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

while循环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

# 监控磁盘使用率
while true; do
    USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
    if [ $USAGE -gt 80 ]; then
        echo "警告:磁盘使用率 ${USAGE}% 超过80%!"
        # 这里可以发邮件或钉钉通知
    fi
    sleep 300  # 每5分钟检查一次
done

函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash

# 定义函数
check_service() {
    local service=$1  # local关键字定义局部变量
    if systemctl is-active --quiet $service; then
        echo "[OK] $service 正在运行"
        return 0
    else
        echo "[FAIL] $service 未运行"
        return 1
    fi
}

# 带返回值的函数
get_cpu_usage() {
    local usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')
    echo $usage
}

# 调用函数
check_service nginx
check_service mysql
check_service redis

CPU=$(get_cpu_usage)
echo "CPU使用率: ${CPU}%"

实用脚本示例:服务器健康检查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/bin/bash
# server_check.sh - 服务器健康检查脚本

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

echo "========== 服务器健康检查 =========="
echo "时间: $(date)"
echo "主机: $(hostname)"
echo "======================================"

# 系统信息
echo -e "\n[系统信息]"
echo "内核: $(uname -r)"
echo "运行时间: $(uptime -p)"

# CPU使用率
echo -e "\n[CPU]"
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f", $2}')
if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
    echo -e "${RED}CPU使用率: ${CPU_USAGE}% [警告]${NC}"
else
    echo -e "${GREEN}CPU使用率: ${CPU_USAGE}% [正常]${NC}"
fi

# 内存使用
echo -e "\n[内存]"
free -h | awk 'NR==2{printf "已用: %s / 总共: %s (使用率: %s)\n", $3, $2, $3/$2*100"%"}'

# 磁盘使用
echo -e "\n[磁盘]"
df -h | grep -E '^/dev/' | while read line; do
    USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
    MOUNT=$(echo $line | awk '{print $6}')
    if [ $USAGE -gt 80 ]; then
        echo -e "${RED}$MOUNT: ${USAGE}% [警告]${NC}"
    else
        echo -e "${GREEN}$MOUNT: ${USAGE}% [正常]${NC}"
    fi
done

# 关键服务检查
echo -e "\n[服务状态]"
for svc in nginx mysql docker; do
    if systemctl is-active --quiet $svc 2>/dev/null; then
        echo -e "${GREEN}$svc: 运行中${NC}"
    else
        echo -e "${RED}$svc: 未运行${NC}"
    fi
done

echo -e "\n======================================"

运行效果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ chmod +x server_check.sh
$ ./server_check.sh
========== 服务器健康检查 ==========
时间: Mon Jan 14 10:30:00 UTC 2026
主机: myserver
======================================

[系统信息]
内核: 5.15.0-91-generic
运行时间: up 15 days, 3 hours, 22 minutes

[CPU]
CPU使用率: 12.3% [正常]

[内存]
已用: 1.2Gi / 总共: 3.8Gi (使用率: 31.5%)

[磁盘]
/: 45% [正常]

[服务状态]
nginx: 运行中
mysql: 运行中
docker: 运行中
======================================

调试技巧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 方法1:用 -x 参数运行,显示每一步执行
$ bash -x ./script.sh
+ echo 'Hello, World!'
Hello, World!
+ date +%Y-%m-%d
+ TODAY=2026-01-14

# 方法2:在脚本中加set -x
#!/bin/bash
set -x  # 开启调试
# ...你的代码...
set +x  # 关闭调试

# 方法3:set -e 遇到错误立即退出
#!/bin/bash
set -e  # 任何命令失败就退出

总结

Shell脚本的核心就是:把你手动敲的命令组织起来,加上逻辑判断和循环。不需要写得多优雅,能跑、能解决问题就行。

想看更多实用脚本,推荐阅读10个超实用Shell脚本。关于定时执行脚本的方法,可以看Crontab定时任务全攻略

Shell脚本 Bash 自动化运维
cd ..