Shell脚本高级技巧#
Shell脚本是Linux系统管理和自动化的强大工具,掌握高级技巧可以让您编写更加高效、灵活和强大的脚本。本教程将详细介绍Shell脚本中的各种高级技巧,从正则表达式到进程管理,从数组操作到信号处理。
入门#
正则表达式基础#
正则表达式是用于匹配字符串模式的强大工具,在Shell脚本中广泛应用于文本处理。
# 基本正则表达式
# 匹配包含"test"的行
grep "test" file.txt
# 匹配以"test"开头的行
grep "^test" file.txt
# 匹配以"test"结尾的行
grep "test$" file.txt
# 匹配包含数字的行
grep "[0-9]" file.txt
# 匹配包含字母的行
grep "[a-zA-Z]" file.txt
# 匹配包含单词"test"的行(边界匹配)
grep "\\<test\\>" file.txt数组基础#
数组是Shell中存储多个值的变量类型,支持索引数组和关联数组。
# 索引数组定义
fruits=(apple banana cherry date)
# 访问数组元素
echo "第一个元素: ${fruits[0]}"
echo "第二个元素: ${fruits[1]}"
# 访问所有元素
echo "所有元素: ${fruits[@]}"
echo "所有元素: ${fruits[*]}"
# 获取数组长度
echo "数组长度: ${#fruits[@]}"
# 修改数组元素
fruits[2]="grape"
echo "修改后: ${fruits[@]}"
# 添加元素
fruits+=(elderberry)
echo "添加后: ${fruits[@]}"进程管理基础#
# 查看当前进程
ps
# 查看所有进程
ps aux
# 查看特定进程
ps aux | grep "bash"
# 终止进程
kill PID
# 强制终止进程
kill -9 PID
# 后台执行命令
command &
# 查看后台进程
jobs
# 将后台进程调回前台
fg %1
# 暂停进程
Ctrl+Z
# 继续执行暂停的进程
bg %1中级#
高级正则表达式#
扩展正则表达式#
# 使用扩展正则表达式(-E选项)
# 匹配"test"或"exam"
grep -E "test|exam" file.txt
# 匹配重复字符
grep -E "a{2,3}" file.txt # 匹配2-3个连续的a
# 匹配分组
grep -E "(test){2}" file.txt # 匹配"testtest"
# 匹配可选字符
grep -E "colou?r" file.txt # 匹配"color"或"colour"
# 匹配单词边界
grep -E "\\btest\\b" file.txt # 匹配单词"test"正则表达式工具#
# sed命令使用正则表达式
# 替换文本
sed 's/old/new/g' file.txt
# 替换并直接修改文件
sed -i 's/old/new/g' file.txt
# awk命令使用正则表达式
# 按模式匹配行
awk '/test/ {print}' file.txt
# 按模式分割字段
awk -F'[0-9]+' '{print $1}' file.txt
# 正则表达式匹配测试
grep -q "pattern" file.txt && echo "匹配" || echo "不匹配"高级数组操作#
关联数组#
# 定义关联数组
declare -A colors
# 添加元素
colors["red"]="#FF0000"
colors["green"]="#00FF00"
colors["blue"]="#0000FF"
# 访问元素
echo "红色: ${colors["red"]}"
echo "绿色: ${colors[green]}"
# 遍历关联数组
for color in "${!colors[@]}"; do
echo "$color: ${colors[$color]}"
done
# 获取关联数组长度
echo "数组长度: ${#colors[@]}"数组操作#
# 数组切片
numbers=(1 2 3 4 5 6 7 8 9 10)
echo "前3个元素: ${numbers[@]:0:3}" # 从索引0开始,取3个元素
echo "从索引2开始: ${numbers[@]:2}" # 从索引2开始,取所有元素
# 数组排序
sorted=($(echo "${numbers[@]}" | tr ' ' '\n' | sort -n))
echo "排序后: ${sorted[@]}"
# 数组去重
unique=($(echo "${numbers[@]}" | tr ' ' '\n' | uniq))
echo "去重后: ${unique[@]}"
# 数组交集
array1=(1 2 3 4 5)
array2=(3 4 5 6 7)
intersection=($(comm -12 <(echo "${array1[@]}" | tr ' ' '\n' | sort) <(echo "${array2[@]}" | tr ' ' '\n' | sort)))
echo "交集: ${intersection[@]}"
# 数组差集
difference=($(comm -23 <(echo "${array1[@]}" | tr ' ' '\n' | sort) <(echo "${array2[@]}" | tr ' ' '\n' | sort)))
echo "差集: ${difference[@]}"信号处理#
# 基本信号处理
trap 'echo "收到SIGINT信号"' SIGINT
echo "按Ctrl+C测试信号处理"
sleep 10
# 多个信号处理
trap 'echo "收到信号"' SIGINT SIGTERM
# 忽略信号
trap '' SIGINT
echo "按Ctrl+C不会终止脚本"
sleep 10
# 恢复默认信号处理
trap - SIGINT
echo "按Ctrl+C会终止脚本"
sleep 10
# 退出时执行清理
trap 'echo "执行清理"; rm -f temp.txt' EXIT
echo "创建临时文件"
touch temp.txt
sleep 5高级#
进程控制#
进程创建和管理#
# 创建子进程
(child_process) {
echo "子进程PID: $$"
echo "父进程PID: $PPID"
sleep 2
echo "子进程完成"
}
child_process &
parent_pid=$$
echo "父进程PID: $parent_pid"
wait
echo "父进程完成"
# 进程替换
# 同时执行多个命令并捕获输出
paste <(ls *.txt) <(wc -l *.txt | grep -v total)
# 进程间通信
# 使用管道
echo "Hello" | (read msg; echo "收到: $msg")
# 使用命名管道
mkfifo mypipe
echo "写入命名管道" > mypipe &
echo "从命名管道读取: $(cat mypipe)"
rm mypipe进程监控#
# 监控进程状态
watch -n 1 "ps aux | grep 'python'"
# 监控系统负载
watch -n 1 "uptime"
# 监控磁盘I/O
iotop
# 监控网络连接
netstat -tuln
# 监控进程资源使用
top -p PID
# 进程跟踪
strace command高级文本处理#
awk 高级用法#
# awk 基本用法
# 打印文件的第一列
awk '{print $1}' file.txt
# 打印包含"test"的行的第一列
awk '/test/ {print $1}' file.txt
# 使用变量
awk '{sum += $1} END {print sum}' file.txt
# 使用自定义分隔符
awk -F"," '{print $1}' csv_file.txt
# 条件判断
awk '$1 > 10 {print $0}' file.txt
# 循环
awk '{
for (i=1; i<=NF; i++) {
print "字段" i ":" $i
}
}' file.txt
# 数组
awk '{
count[$1]++
} END {
for (word in count) {
print word ":" count[word]
}
}' file.txtsed 高级用法#
# sed 基本用法
# 替换第一处匹配
sed 's/old/new/' file.txt
# 替换所有匹配
sed 's/old/new/g' file.txt
# 替换第n处匹配
sed 's/old/new/2' file.txt
# 使用不同分隔符
sed 's|old|new|g' file.txt
# 删除空行
sed '/^$/d' file.txt
# 删除包含"test"的行
sed '/test/d' file.txt
# 在指定行后插入文本
sed '/test/a new line' file.txt
# 在指定行前插入文本
sed '/test/i new line' file.txt
# 替换指定行范围
sed '1,5s/old/new/g' file.txt系统编程#
文件描述符操作#
# 基本文件描述符
# 0: 标准输入
# 1: 标准输出
# 2: 标准错误
# 重定向标准输出和标准错误
command > output.txt 2>&1
# 自定义文件描述符
# 创建文件描述符3指向文件
exec 3> output.txt
echo "通过文件描述符3输出" >&3
exec 3>&-
# 读写文件描述符
exec 4<> data.txt
echo "写入数据" >&4
seek 0 4
cat <&4
exec 4>&-
# 复制文件描述符
exec 5>&1
echo "输出到标准输出" >&5
exec 5>&-环境变量#
# 查看环境变量
env
# 查看特定环境变量
echo $HOME
echo $PATH
# 设置环境变量
export MY_VAR="value"
echo $MY_VAR
# 临时修改环境变量
PATH=/usr/local/bin:$PATH command
# 移除环境变量
unset MY_VAR
# 环境变量持久化
# 在~/.bashrc或~/.bash_profile中添加
export MY_VAR="value"
# 加载环境变量
source ~/.bashrc大师#
高级脚本设计#
模块化脚本#
# 模块定义
# utils.sh
#!/bin/bash
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@"
}
# 文件检查函数
check_file() {
local file=$1
[ -f "$file" ] && [ -r "$file" ]
}
# 导出函数
export -f log
export -f check_file
# 主脚本
#!/bin/bash
# 导入模块
source utils.sh
# 使用模块函数
log "开始执行脚本"
if check_file "data.txt"; then
log "数据文件存在"
else
log "数据文件不存在"
fi
log "脚本执行完成"配置管理#
# 配置文件
# config.sh
#!/bin/bash
# 默认配置
CONFIG_DIR="/etc/myapp"
LOG_FILE="/var/log/myapp.log"
DEBUG=false
# 加载用户配置
if [ -f "~/.myapp/config.sh" ]; then
source "~/.myapp/config.sh"
fi
# 命令行参数覆盖
while getopts "d:l:v" opt; do
case $opt in
d)
CONFIG_DIR=$OPTARG
;;
l)
LOG_FILE=$OPTARG
;;
v)
DEBUG=true
;;
esac
done
# 主脚本
#!/bin/bash
# 加载配置
source config.sh
# 使用配置
echo "配置目录: $CONFIG_DIR"
echo "日志文件: $LOG_FILE"
echo "调试模式: $DEBUG"性能优化#
脚本性能优化#
# 减少命令执行次数
# 不好的做法
for file in *.txt; do
wc -l "$file"
done
# 好的做法
wc -l *.txt
# 减少文件I/O
# 不好的做法
for i in {1..1000}; do
echo "$i" >> output.txt
done
# 好的做法
{
for i in {1..1000}; do
echo "$i"
done
} > output.txt
# 减少子shell
# 不好的做法
for i in $(seq 1 1000); do
echo $i
done
# 好的做法
for i in {1..1000}; do
echo $i
done
# 使用更快的命令
# 不好的做法
ps aux | grep "bash" | wc -l
# 好的做法
pgrep -c "bash"
# 并行执行
# 不好的做法
for file in *.txt; do
process_file "$file"
done
# 好的做法
find . -name "*.txt" | xargs -P 4 -I {} process_file "{}"内存管理#
# 减少内存使用
# 处理大文件时使用流式处理
# 不好的做法
content=$(cat large_file.txt)
process "$content"
# 好的做法
cat large_file.txt | process
# 释放变量
large_variable="big content"
# 使用变量
unset large_variable
# 限制命令内存使用
ulimit -m 1024000 # 限制为1GB
memory_intensive_command
# 监控内存使用
while true; do
mem_usage=$(ps -o rss= -p $$)
echo "当前内存使用: $mem_usage KB"
sleep 1
done安全编程#
安全实践#
# 输入验证
validate_input() {
local input=$1
# 只允许字母和数字
if [[ ! "$input" =~ ^[a-zA-Z0-9]+$ ]]; then
echo "错误: 输入包含非法字符"
return 1
fi
return 0
}
# 命令注入防护
safe_exec() {
local cmd=$1
# 检查命令是否安全
if [[ "$cmd" =~ [;&|<>] ]]; then
echo "错误: 命令包含非法字符"
return 1
fi
eval "$cmd"
}
# 路径遍历防护
safe_path() {
local path=$1
# 解析绝对路径
real_path=$(realpath "$path")
# 检查是否在允许的目录内
if [[ ! "$real_path" =~ ^/allowed/dir ]]; then
echo "错误: 路径超出允许范围"
return 1
fi
echo "$real_path"
}
# 权限检查
check_permissions() {
if [ $(id -u) -ne 0 ]; then
echo "错误: 需要root权限"
return 1
fi
return 0
}加密和哈希#
# 生成随机密码
openssl rand -base64 12
# 加密文件
openssl enc -aes-256-cbc -salt -in plaintext.txt -out encrypted.txt
# 解密文件
openssl enc -d -aes-256-cbc -in encrypted.txt -out decrypted.txt
# 生成文件哈希
md5sum file.txt
sha256sum file.txt
# 密码哈希
echo "password" | sha256sum
# 验证哈希
if [ "$(echo "password" | sha256sum)" = "expected_hash" ]; then
echo "密码正确"
else
echo "密码错误"
fi无敌#
高级系统集成#
网络编程#
# 基本网络操作
# 检查网络连接
ping -c 1 google.com
# 检查端口
nc -z google.com 80
# 简单HTTP请求
curl http://example.com
# 下载文件
wget http://example.com/file.txt
# 创建简单的HTTP服务器
python3 -m http.server 8080
# 网络套接字
# 使用nc创建服务器
nc -l 8080
# 使用nc连接服务器
nc localhost 8080
# 传输文件
# 接收端
nc -l 8080 > received_file.txt
# 发送端
nc localhost 8080 < send_file.txt数据库操作#
# SQLite操作
# 创建数据库
sqlite3 mydb.db "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT);"
# 插入数据
sqlite3 mydb.db "INSERT INTO users (name, email) VALUES ('John', 'john@example.com');"
# 查询数据
sqlite3 mydb.db "SELECT * FROM users;"
# MySQL/MariaDB操作
# 连接数据库
mysql -u user -p database
# 执行SQL命令
mysql -u user -p database -e "SELECT * FROM users;"
# PostgreSQL操作
# 连接数据库
psql -U user -d database
# 执行SQL命令
psql -U user -d database -c "SELECT * FROM users;"高级工具集成#
Git 集成#
# Git 基本操作
git status
git add .
git commit -m "提交消息"
git push
# Git 分支
git branch
git checkout branch_name
git merge branch_name
# Git 日志
git log
git log --oneline
# Git 标签
git tag v1.0
git push --tags
# Git 钩子
# .git/hooks/pre-commit
#!/bin/bash
# 运行测试
echo "运行测试..."
if ! ./run_tests.sh; then
echo "测试失败,取消提交"
exit 1
fi
echo "测试通过,继续提交"
exit 0Docker 集成#
# Docker 基本操作
docker ps
docker images
docker run -it ubuntu bash
# Docker 构建
docker build -t myapp .
# Docker 运行
docker run -d -p 8080:80 myapp
# Docker Compose
docker-compose up -d
docker-compose down
# Docker 脚本
# docker_deploy.sh
#!/bin/bash
# 构建镜像
docker build -t myapp:$(date +%Y%m%d) .
# 停止旧容器
docker stop myapp || true
docker rm myapp || true
# 运行新容器
docker run -d --name myapp -p 8080:80 myapp:$(date +%Y%m%d)
echo "部署完成"实用脚本示例#
系统管理工具#
#!/bin/bash
# 系统管理工具
# 显示系统信息
show_system_info() {
echo "===== 系统信息 ====="
uname -a
echo ""
echo "===== 硬件信息 ====="
lscpu
echo ""
echo "===== 内存信息 ====="
free -h
echo ""
echo "===== 磁盘信息 ====="
df -h
echo ""
echo "===== 网络信息 ====="
ip addr
echo ""
}
# 服务管理
manage_service() {
local action=$1
local service=$2
case $action in
start)
sudo systemctl start "$service"
;;
stop)
sudo systemctl stop "$service"
;;
restart)
sudo systemctl restart "$service"
;;
status)
sudo systemctl status "$service"
;;
*)
echo "无效操作: $action"
return 1
;;
esac
}
# 系统监控
monitor_system() {
local interval=5
local count=10
for ((i=1; i<=count; i++)); do
clear
echo "===== 系统监控 (第$i/$count次) ====="
echo "CPU使用:"
top -bn1 | grep "Cpu(s)"
echo "\n内存使用:"
free -h
echo "\n磁盘I/O:"
iostat
echo "\n网络流量:"
netstat -i
if [ $i -lt $count ]; then
sleep $interval
fi
done
}
# 主菜单
show_menu() {
echo "===== 系统管理工具 ====="
echo "1. 显示系统信息"
echo "2. 管理服务"
echo "3. 系统监控"
echo "4. 退出"
echo "===================="
}
# 主循环
while true; do
show_menu
read -p "请选择: " choice
case $choice in
1)
show_system_info
;;
2)
read -p "输入操作(start/stop/restart/status): " action
read -p "输入服务名: " service
manage_service "$action" "$service"
;;
3)
monitor_system
;;
4)
echo "再见!"
exit 0
;;
*)
echo "无效选择"
;;
esac
echo "按Enter键继续..."
read
done数据处理工具#
#!/bin/bash
# 数据处理工具
# CSV文件处理
process_csv() {
local file=$1
echo "===== CSV文件处理 ====="
echo "文件: $file"
echo "行数: $(wc -l < "$file")"
echo ""
# 显示前5行
echo "前5行:"
head -5 "$file"
echo ""
# 统计列数
columns=$(head -1 "$file" | tr ',' '\n' | wc -l)
echo "列数: $columns"
echo ""
# 显示列名
echo "列名:"
head -1 "$file" | tr ',' '\n' | nl
echo ""
# 按列排序
read -p "输入排序列号: " sort_col
echo "按列$sort_col排序:"
sort -t',' -k"$sort_col" "$file" | head -10
}
# 日志分析
analyze_log() {
local file=$1
echo "===== 日志分析 ====="
echo "文件: $file"
echo "行数: $(wc -l < "$file")"
echo ""
# 统计错误数
error_count=$(grep -c "ERROR" "$file")
echo "错误数: $error_count"
echo ""
# 统计警告数
warning_count=$(grep -c "WARNING" "$file")
echo "警告数: $warning_count"
echo ""
# 显示最近的错误
echo "最近的错误:"
grep "ERROR" "$file" | tail -10
echo ""
# 显示最近的警告
echo "最近的警告:"
grep "WARNING" "$file" | tail -10
}
# 文本转换
convert_text() {
local file=$1
local operation=$2
case $operation in
upper)
echo "转换为大写:"
tr '[:lower:]' '[:upper:]' < "$file" | head -10
;;
lower)
echo "转换为小写:"
tr '[:upper:]' '[:lower:]' < "$file" | head -10
;;
title)
echo "转换为标题格式:"
sed 's/\b\(\w\)/\U\1/g' < "$file" | head -10
;;
reverse)
echo "反转每行:"
rev < "$file" | head -10
;;
*)
echo "无效操作"
;;
esac
}
# 主菜单
show_menu() {
echo "===== 数据处理工具 ====="
echo "1. CSV文件处理"
echo "2. 日志分析"
echo "3. 文本转换"
echo "4. 退出"
echo "===================="
}
# 主循环
while true; do
show_menu
read -p "请选择: " choice
case $choice in
1)
read -p "输入CSV文件路径: " csv_file
if [ -f "$csv_file" ]; then
process_csv "$csv_file"
else
echo "文件不存在"
fi
;;
2)
read -p "输入日志文件路径: " log_file
if [ -f "$log_file" ]; then
analyze_log "$log_file"
else
echo "文件不存在"
fi
;;
3)
read -p "输入文本文件路径: " text_file
if [ -f "$text_file" ]; then
echo "1. 转换为大写"
echo "2. 转换为小写"
echo "3. 转换为标题格式"
echo "4. 反转每行"
read -p "请选择操作: " op_choice
case $op_choice in
1)
convert_text "$text_file" upper
;;
2)
convert_text "$text_file" lower
;;
3)
convert_text "$text_file" title
;;
4)
convert_text "$text_file" reverse
;;
*)
echo "无效选择"
;;
esac
else
echo "文件不存在"
fi
;;
4)
echo "再见!"
exit 0
;;
*)
echo "无效选择"
;;
esac
echo "按Enter键继续..."
read
done总结#
Shell脚本高级技巧是提升脚本编写能力的关键,通过掌握正则表达式、数组操作、进程管理、信号处理等高级技术,您可以编写更加高效、灵活和强大的Shell脚本。从简单的文本处理到复杂的系统管理,Shell脚本都能胜任。
本教程涵盖了Shell脚本的各种高级技巧,包括正则表达式、数组操作、进程管理、信号处理、模块化设计、性能优化和安全编程等内容。通过学习和实践这些技巧,您将能够编写更加专业、可靠的Shell脚本,解决各种复杂的系统管理和自动化任务。
记住,Shell脚本的威力在于其简洁性和灵活性,结合Linux系统的各种工具和命令,可以实现几乎无限的可能性。不断学习和实践,您将成为Shell脚本的大师。