Shell 脚本核心教程(Bash 为主)
本文档聚焦 Linux 系统中最常用的 Bash Shell,整理了 Shell 脚本的基础语法、核心命令、流程控制、实战技巧和常用示例,适合新手快速入门并能解决日常运维场景需求。
一、Shell 基础
1. 什么是 Shell
Shell 是操作系统的命令解释器,是用户与 Linux 内核交互的桥梁。Bash(Bourne-Again Shell)是绝大多数 Linux 发行版的默认 Shell。
2. 第一个 Shell 脚本
(1)创建脚本文件
touch hello.sh # 创建脚本文件
vim hello.sh # 编辑脚本
(2)脚本内容
#!/bin/bash
# 这是注释:第一个 Shell 脚本
echo "Hello, Shell!" # 输出内容到控制台
(3)执行脚本的3种方式
# 方式1:赋予执行权限后直接运行(推荐)
chmod +x hello.sh
./hello.sh
# 方式2:通过 bash 命令执行(无需执行权限)
bash hello.sh
# 方式3:在当前 Shell 环境执行(会影响当前环境,慎用)
source hello.sh
# 或简写
. hello.sh
3. 脚本头部声明(Shebang)
#!/bin/bash:指定使用 Bash 解释器(最常用)#!/bin/sh:指定使用系统默认 Shell(通常是 Bash 的软链接)#!/usr/bin/env bash:自动查找系统中的 Bash 路径(跨平台友好)
二、Shell 变量
1. 变量定义与使用
(1)基本规则
- 变量名只能包含字母、数字、下划线,且不能以数字开头;
- 赋值时
=两边无空格; - 使用变量需加
$,推荐用${变量名}避免歧义。
(2)示例
#!/bin/bash
# 定义普通变量
name="张三"
age=25
readonly PI=3.14159 # 只读变量(不可修改)
unset age # 删除变量(只读变量无法删除)
# 使用变量
echo "姓名:$name"
echo "年龄:${age}" # 推荐写法,避免和后续字符混淆
echo "圆周率:${PI}"
2. 特殊变量(内置变量)
| 变量 | 说明 | 示例 |
|---|---|---|
$0 |
脚本文件名 | echo "脚本名:$0" |
$1-$9 |
脚本的位置参数(第1-9个参数) | 执行 ./test.sh 10 20 时,$1=10,$2=20 |
${10} |
第10个及以上参数(必须加花括号) | - |
$# |
位置参数的个数 | echo "参数个数:$#" |
$* |
所有位置参数(视为一个整体) | - |
$@ |
所有位置参数(视为独立个体) | - |
$? |
上一条命令的退出状态码(0=成功,非0=失败) | echo "上条命令执行结果:$?" |
$$ |
当前脚本的进程ID(PID) | echo "脚本PID:$$" |
$! |
最后一个后台进程的PID | - |
示例:位置参数使用
#!/bin/bash
echo "脚本名:$0"
echo "第1个参数:$1"
echo "第2个参数:$2"
echo "参数总数:$#"
echo "所有参数:$@"
# 遍历所有参数
for arg in "$@"; do
echo "参数:$arg"
done
执行:./param.sh 苹果 香蕉 橘子,输出:
脚本名:./param.sh
第1个参数:苹果
第2个参数:香蕉
参数总数:3
所有参数:苹果 香蕉 橘子
参数:苹果
参数:香蕉
参数:橘子
3. 环境变量
-
查看所有环境变量:
env或printenv -
常用环境变量:
PATH:命令搜索路径(如/usr/bin:/bin)HOME:当前用户主目录PWD:当前工作目录USER:当前用户名SHELL:当前使用的 Shell
-
设置环境变量(临时生效):
export PATH=$PATH:/usr/local/mybin # 添加自定义命令路径 -
永久生效:将上述命令写入
~/.bashrc(当前用户)或/etc/profile(所有用户),执行source ~/.bashrc生效。
三、字符串操作
1. 字符串定义
str1='单引号字符串' # 单引号:原样输出,不解析变量和转义字符
str2="双引号字符串:${name}" # 双引号:解析变量和转义字符
str3=无引号字符串 # 无引号:和双引号类似,但不能包含空格
2. 核心操作
| 操作 | 语法 | 示例 |
|---|---|---|
| 获取长度 | ${#字符串} |
len=${#str2}; echo $len |
| 截取子串 | ${字符串:起始位置:长度} |
str="hello world"; echo ${str:0:5} → hello |
| 替换 | ${字符串/旧值/新值}(替换第一个) |
${str/world/shell} → hello shell |
| 替换 | ${字符串//旧值/新值}(替换所有) |
${str/l/L} → heLLo worLd |
| 删除前缀 | ${字符串#匹配规则}(最短匹配) |
str="a1b1c1"; echo ${str#*1} → b1c1 |
| 删除前缀 | ${字符串##匹配规则}(最长匹配) |
${str##*1} → c1 |
| 删除后缀 | ${字符串%匹配规则}(最短匹配) |
${str%1*} → a1b |
| 删除后缀 | ${字符串%%匹配规则}(最长匹配) |
${str%%1*} → a |
四、流程控制
1. 条件判断(if)
(1)基本语法
# 单分支
if [ 条件表达式 ]; then
执行语句
fi
# 双分支
if [ 条件表达式 ]; then
执行语句1
else
执行语句2
fi
# 多分支
if [ 条件表达式1 ]; then
执行语句1
elif [ 条件表达式2 ]; then
执行语句2
else
执行语句3
fi
(2)条件表达式(常用)
| 类型 | 语法 | 说明 |
|---|---|---|
| 文件判断 | -f 文件 |
判断是否为普通文件 |
-d 文件 |
判断是否为目录 | |
-e 文件 |
判断文件/目录是否存在 | |
-r 文件 |
判断是否有读权限 | |
-w 文件 |
判断是否有写权限 | |
-x 文件 |
判断是否有执行权限 | |
| 字符串判断 | [ "$str1" = "$str2" ] |
判断字符串相等(= 两边有空格) |
[ "$str1" != "$str2" ] |
判断字符串不相等 | |
[ -z "$str" ] |
判断字符串为空 | |
[ -n "$str" ] |
判断字符串非空 | |
| 数值判断 | [ $num1 -eq $num2 ] |
等于(equal) |
[ $num1 -ne $num2 ] |
不等于(not equal) | |
[ $num1 -gt $num2 ] |
大于(greater than) | |
[ $num1 -lt $num2 ] |
小于(less than) | |
[ $num1 -ge $num2 ] |
大于等于(greater equal) | |
[ $num1 -le $num2 ] |
小于等于(less equal) | |
| 逻辑判断 | [ 条件1 ] && [ 条件2 ] |
且(两个条件都成立) |
[ 条件1 ] || [ 条件2 ] |
或(任一条件成立) | |
! [ 条件 ] |
非(条件不成立) |
示例:文件存在判断
#!/bin/bash
file="/etc/passwd"
if [ -f "$file" ]; then
echo "$file 是普通文件"
elif [ -d "$file" ]; then
echo "$file 是目录"
else
echo "$file 不存在"
fi
2. 分支选择(case)
适合多值匹配场景,替代多层 if-elif。
#!/bin/bash
read -p "请输入数字(1-3):" num
case $num in
1)
echo "你输入了1"
;;
2)
echo "你输入了2"
;;
3)
echo "你输入了3"
;;
*)
echo "输入无效,请输入1-3的数字"
;;
esac
3. 循环
(1)for 循环
# 方式1:遍历列表
for i in 1 2 3 4 5; do
echo "数字:$i"
done
# 方式2:遍历文件
for file in /root/*; do
echo "文件:$file"
done
# 方式3:C语言风格
for ((i=0; i<5; i++)); do
echo "循环次数:$i"
done
(2)while 循环(条件为真时执行)
#!/bin/bash
i=1
while [ $i -le 5 ]; do
echo "当前值:$i"
i=$((i+1)) # 数值自增
done
(3)until 循环(条件为假时执行)
#!/bin/bash
i=1
until [ $i -gt 5 ]; do
echo "当前值:$i"
i=$((i+1))
done
(4)循环控制
break:跳出当前循环continue:跳过本次循环,继续下一次
#!/bin/bash
for i in 1 2 3 4 5; do
if [ $i -eq 3 ]; then
continue # 跳过3
fi
if [ $i -eq 5 ]; then
break # 跳出循环
fi
echo "数字:$i"
done
五、函数
1. 函数定义与调用
#!/bin/bash
# 定义函数
say_hello() {
local name=$1 # local 定义局部变量(仅函数内有效)
echo "你好,$name!"
return 0 # 返回值(0-255,默认0为成功)
}
# 调用函数
say_hello "李四"
echo "函数返回值:$?" # 获取返回值
2. 函数参数
函数内使用 $1-$9、$#、$@ 等特殊变量获取参数,和脚本参数规则一致。
#!/bin/bash
# 计算两个数的和
add() {
local num1=$1
local num2=$2
sum=$((num1 + num2))
echo "和为:$sum"
}
add 10 20 # 调用:输出 和为:30
六、常用工具/命令
1. 输入输出
echo:输出内容(echo -e解析转义字符,如echo -e "hello\nworld")read:读取用户输入(read -p "提示语:" 变量名)printf:格式化输出(类似 C 语言,printf "姓名:%s,年龄:%d\n" "$name" "$age")
2. 文本处理
grep:过滤文本(grep "error" log.txt查找包含error的行)sed:流编辑(sed 's/old/new/g' file.txt替换文件中所有old为new)awk:文本分析(awk '{print $1}' file.txt输出文件第一列)cut:截取列(cut -d ":" -f 1 /etc/passwd以:分隔,截取第一列)
3. 其他常用
date:日期时间(date "+%Y-%m-%d %H:%M:%S"输出 2025-12-31 10:00:00)mkdir/rm:创建/删除目录/文件cp/mv:复制/移动文件find:查找文件(find /root -name "*.sh"查找root下所有.sh文件)wc:统计(wc -l file.txt统计文件行数)
七、实战示例
示例1:批量创建用户
#!/bin/bash
# 批量创建用户,密码统一为 123456
users=("user1" "user2" "user3")
for user in "${users[@]}"; do
# 判断用户是否存在
if id "$user" &>/dev/null; then
echo "$user 已存在,跳过"
else
useradd "$user"
echo "123456" | passwd --stdin "$user" &>/dev/null
echo "$user 创建成功"
fi
done
示例2:日志清理脚本
#!/bin/bash
# 清理7天前的日志文件
log_dir="/var/log/myapp"
if [ -d "$log_dir" ]; then
# 查找7天前的.log文件并删除
find "$log_dir" -name "*.log" -mtime +7 -exec rm -f {} \;
echo "$(date +%Y-%m-%d):已清理 $log_dir 下7天前的日志" >> /var/log/clean_log.log
else
echo "日志目录 $log_dir 不存在"
exit 1
fi
示例3:监控进程是否运行
#!/bin/bash
# 监控nginx进程,若未运行则启动
process="nginx"
if ! pgrep "$process" &>/dev/null; then
echo "$(date):$process 未运行,启动中..." >> /var/log/process_monitor.log
systemctl start nginx
# 检查启动是否成功
if [ $? -eq 0 ]; then
echo "$(date):$process 启动成功" >> /var/log/process_monitor.log
else
echo "$(date):$process 启动失败" >> /var/log/process_monitor.log
fi
else
echo "$(date):$process 运行正常" >> /var/log/process_monitor.log
fi
八、脚本调试与规范
1. 脚本调试
- 执行时调试:
bash -x 脚本名.sh(显示每一行执行的命令和结果) - 脚本内调试:在脚本头部添加
set -x(开启调试),set +x(关闭调试)
2. 编写规范
- 脚本头部添加注释(功能、作者、创建时间、参数说明);
- 变量名、函数名使用小写+下划线(如
log_dir、clean_log); - 关键操作添加日志输出,便于排查问题;
- 对文件/目录、权限等做前置判断,避免脚本异常退出;
- 避免使用绝对路径(除非必要),或通过变量定义路径。
总结
- Shell 脚本核心语法:变量定义 → 流程控制(if/case/循环)→ 函数 → 命令调用;
- 条件判断是重点:牢记文件、字符串、数值的判断语法,注意
[]内的空格; - 实战技巧:善用
grep/sed/awk处理文本,find查找文件,date处理时间; - 调试与规范:用
bash -x调试,遵循命名和注释规范,提升脚本可维护性。
如需查看具体命令的用法,执行 命令 --help(如 grep --help)或 man 命令(如 man bash)查看详细手册。