为什么要学Shell脚本
如果你发现自己经常重复执行一组命令,那就该写脚本了。比如我每次部署代码要执行5个命令——拉代码、编译、停服务、复制文件、起服务。写成脚本后一键搞定,效率提升不止一点。
Shell脚本不需要安装任何东西,Linux自带Bash就能跑。
第一个Shell脚本
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表示成功 |
$$ | 当前进程PID | 12345 |
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定时任务全攻略。