Shell脚本进阶指南:从基础变量到高级实践
一、Shell脚本基础操作与调试技巧
1.1 脚本创建与执行方式
Shell脚本是自动化运维的核心工具,创建脚本的基本流程如下:
# 创建并编辑脚本
vim ip_info.sh# 写入脚本内容(获取IP地址信息)
#!/bin/bash
ifconfig ens33 | grep -w inet | awk '{print $2}' | xargs echo "IP: "# 三种执行方式
bash ip_info.sh # 直接使用bash解释器执行
chmod +x ip_info.sh # 添加可执行权限
./ip_info.sh # 通过路径执行
source ip_info.sh # 在当前Shell环境执行(会继承环境变量)
1.2 脚本调试技巧
调试是编写高质量脚本的关键环节,常用调试选项:
bash -n script.sh # 仅检查语法错误,不执行脚本
bash -v script.sh # 先显示脚本内容,再执行并输出结果
bash -x script.sh # 打印执行的每条命令及其参数(最常用)# 示例:调试带错误的脚本
#!/bin/bash
echo "开始调试"
ls /nonexistent # 故意写错目录
echo "调试结束"# 使用-x选项查看执行过程
bash -x debug_demo.sh
二、Shell变量深度解析
2.1 变量分类与作用域
Shell变量分为三类,其作用域与生命周期各有不同:
# 局部变量(仅当前Shell会话有效)
local_var="local_value"
echo $local_var# 全局变量(所有子Shell均可访问)
export global_var="global_value"
echo $global_var# Shell内置变量(由Shell自动维护)
echo "当前脚本名: $0"
echo "第一个参数: $1"
echo "参数总数: $#"
echo "上条命令返回值: $?"
2.2 变量类型声明
declare命令可显式指定变量类型:
# 整数类型
declare -i num=100
echo $((num + 200)) # 输出300# 只读变量
declare -r readonly_var="固定值"
readonly_var="尝试修改" # 会报错# 数组变量
declare -a array=("元素1" "元素2")
echo ${array[1]} # 输出"元素2"
2.3 命令替换与变量嵌套
将命令执行结果赋值给变量的两种方式:
# 反引号方式
current_dir=`pwd`
echo "当前目录: $current_dir"# $()方式(更推荐)
os_version=$(cat /etc/redhat-release)
echo "操作系统: $os_version"# 复杂示例:获取当前登录用户数
user_count=$(who | wc -l)
echo "当前登录用户: $user_count"
三、字符串操作高级技巧
3.1 字符串长度与截取
str="hello_world_2025"# 获取字符串长度
echo ${#str} # 输出16# 字符串截取
echo ${str:0:5} # 从0开始截取5个字符,输出"hello"
echo ${str:6:5} # 从第6位开始截取5个,输出"world"
echo ${str: -4} # 截取最后4个字符,注意-前有空格,输出"2025"
echo ${str:0-6:3} # 从倒数第6位开始取3个,输出"rld"
3.2 字符串替换与默认值
# 替换第一个匹配项
url="https://example.com"
echo ${url/https/http} # 输出"http://example.com"# 替换所有匹配项
text="hello world, hello shell"
echo ${text//hello/hi} # 输出"hi world, hi shell"# 变量默认值
username=${USERNAME:-"guest"} # 如果USERNAME未定义,则使用"guest"
echo "欢迎 $username"
四、特殊变量与脚本参数处理
4.1 特殊变量详解
#!/bin/bash
# 演示特殊变量的使用
echo "脚本名: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "参数总数: $#"
echo "所有参数: $@"
echo "所有参数(单字符串): $*"
echo "当前进程ID: $$"
echo "后台进程ID: $!"
echo "上条命令返回值: $?"
执行示例:
./special_vars.sh apple banana
# 输出:
# 脚本名: ./special_vars.sh
# 第一个参数: apple
# 第二个参数: banana
# 参数总数: 2
# 所有参数: apple banana
# 所有参数(单字符串): apple banana
# 当前进程ID: 12345
# 后台进程ID: 12346
# 上条命令返回值: 0
4.2 参数处理示例
编写一个接收文件路径并显示文件信息的脚本:
#!/bin/bash
# 文件信息脚本if [ $# -eq 0 ]; thenecho "请提供一个文件路径作为参数"exit 1
fifile_path=$1
echo "文件路径: $file_path"
echo "文件大小: $(du -h $file_path | awk '{print $1}')"
echo "文件权限: $(ls -l $file_path | awk '{print $1}')"
echo "创建时间: $(stat -c %y $file_path)"
五、高级实践案例
5.1 嵌套Shell环境变量传递
演示父子Shell之间的变量继承关系:
# 父脚本 father.sh
#!/bin/bash
export PARENT_VAR="父脚本变量"
echo "父脚本: $PARENT_VAR"
bash child.sh # 启动子Shell
echo "父脚本执行完毕"# 子脚本 child.sh
#!/bin/bash
echo "子脚本: $PARENT_VAR" # 可以访问父Shell的全局变量
local CHILD_VAR="子脚本变量"
echo "子脚本: $CHILD_VAR"
5.2 交互式菜单脚本
创建一个简单的系统信息查询菜单:
#!/bin/bash
# 系统信息菜单脚本while true; doecho "===== 系统信息菜单 ====="echo "1. 查看CPU信息"echo "2. 查看内存使用"echo "3. 查看磁盘空间"echo "4. 查看网络连接"echo "5. 退出"echo "======================="read -p "请选择(1-5): " choicecase $choice in1) lscpu ;;2) free -h ;;3) df -Th ;;4) netstat -tulpn ;;5) echo "退出菜单"; exit 0 ;;*) echo "无效选择,请重试" ;;esacecho
done
5.3 日志分析脚本
统计Nginx访问日志中每个IP的请求次数:
#!/bin/bash
# Nginx日志分析脚本if [ $# -eq 0 ]; thenlog_file="/var/log/nginx/access.log"
elselog_file=$1
fiif [ ! -f $log_file ]; thenecho "日志文件不存在: $log_file"exit 1
fiecho "正在分析日志: $log_file"
echo "IP地址统计Top 10:"
cat $log_file | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
六、最佳实践与避坑指南
6.1 脚本编写规范
- 始终在脚本开头添加
#!/bin/bash
指定解释器 - 使用
set -e
让脚本在遇到错误时立即退出 - 变量名使用大写字母(区分内置变量)
- 对所有变量加双引号,防止分词问题:
"$var"
- 使用函数组织代码,提高复用性
6.2 常见错误处理
# 检查命令执行状态
result=$(some_command)
if [ $? -ne 0 ]; thenecho "命令执行失败"exit 1
fi# 使用&&和||组合命令
mkdir /tmp/my_dir && echo "目录创建成功" || echo "目录创建失败"# 捕获错误并记录日志
function cleanup {echo "清理临时文件..."rm -f /tmp/temp_file.*
}
trap cleanup EXIT # 脚本退出时执行清理
通过掌握这些Shell脚本技术,你可以高效完成系统管理、自动化部署、数据处理等任务,成为运维和开发工作中的多面手。