1. Shell笔记的价值与使用场景
作为一个在Linux环境下摸爬滚打多年的老运维,我始终认为Shell脚本是每个技术人员必须掌握的生存技能。2026年1月7日这天的笔记,记录了我解决一个复杂日志分析问题的完整过程,也包含了许多实战中积累的Shell编程技巧。
Shell脚本之所以重要,是因为它能在几乎所有Unix-like系统上运行,无需额外环境配置。从简单的文件批量重命名,到复杂的系统监控和自动化部署,Shell都能胜任。我的这份笔记特别适合以下几类读者:
- 刚接触Linux需要快速上手Shell的新手
- 日常需要处理文本、日志的运维人员
- 想提高自动化脚本编写效率的中级用户
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Shell基础核心语法精要
2.1 变量与参数处理
Shell中的变量使用看似简单,但有很多细节需要注意:
bash复制# 正确赋值方式
filename="access.log.20260107"
count=100
# 错误示例:等号两边有空格
count = 100 # 这将报错
# 使用变量
echo "Processing $filename" # 双引号内变量会被解析
echo 'Today is $date' # 单引号内保持原样
特殊变量在实际脚本中非常有用:
bash复制echo "脚本名称: $0" # 当前脚本名
echo "第一个参数: $1" # 传入的第一个参数
echo "参数个数: $#" # 传入参数总数
echo "所有参数: $@" # 所有参数列表
echo "上条命令结果: $?" # 上条命令退出状态
2.2 流程控制实战技巧
if语句的方括号两边必须有空格:
bash复制if [ -f "/var/log/$filename" ]; then
echo "文件存在"
elif [ -d "/var/log" ]; then
echo "目录存在"
else
echo "路径无效"
fi
for循环处理文件列表时的最佳实践:
bash复制# 避免使用ls直接循环,用通配符更安全
for logfile in /var/log/*.log; do
[ -e "$logfile" ] || continue # 处理文件不存在的情况
echo "Processing: $logfile"
done
while读取文件内容的标准写法:
bash复制while IFS= read -r line; do
echo "Line: $line"
done < "$filename"
3. 文本处理三剑客深度应用
3.1 grep高效搜索模式
排除注释和空行的实用技巧:
bash复制grep -vE '^\s*(#|$)' config.conf # 排除注释和空行
递归搜索时排除特定目录:
bash复制grep -r --exclude-dir={.git,node_modules} "error" /project
3.2 sed流编辑器的魔法
就地修改文件的安全做法(先备份):
bash复制sed -i.bak 's/old/new/g' file.txt # 自动创建file.txt.bak
多命令组合的清晰写法:
bash复制sed -e '/^#/d' -e '/^$/d' -e 's/foo/bar/' config.conf
3.3 awk数据处理专家
统计日志中不同状态码的出现次数:
bash复制awk '{status[$9]++} END {for(s in status) print s, status[s]}' access.log
提取特定列并计算平均值:
bash复制awk '{sum+=$3; count++} END {print "Avg:", sum/count}' data.txt
4. 实用脚本开发模式
4.1 安全的脚本模板
一个健壮的脚本应该包含以下要素:
bash复制#!/bin/bash
set -euo pipefail # 严格模式:错误退出、未定义变量报错、管道错误检测
usage() {
echo "Usage: $0 [options] <input>"
exit 1
}
# 参数解析
while getopts ":hv" opt; do
case $opt in
h) usage ;;
v) verbose=1 ;;
\?) echo "Invalid option: -$OPTARG" >&2 ;;
esac
done
shift $((OPTIND-1))
[ $# -eq 0 ] && usage
main() {
local input="$1"
# 业务逻辑
}
main "$@"
4.2 日志分析实战案例
分析Nginx日志获取TOP 10访问IP:
bash复制awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10
监控磁盘使用率的守护脚本:
bash复制#!/bin/bash
THRESHOLD=90
INTERVAL=300
while true; do
usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
[ "$usage" -ge "$THRESHOLD" ] && \
mail -s "Disk Alert" admin@example.com <<< "Disk usage: $usage%"
sleep $INTERVAL
done
5. 高级技巧与性能优化
5.1 避免常见性能陷阱
- 循环内调用外部命令:
bash复制# 错误示范:每次循环都调用grep
for file in *; do
grep "pattern" "$file"
done
# 正确做法:使用shell内置功能
for file in *; do
[[ -f "$file" ]] && [[ "$file" == *.log ]] || continue
# 处理文件
done
- 大量小文件处理时使用find+xargs:
bash复制# 比for循环效率高得多
find . -name "*.log" -print0 | xargs -0 grep "error"
5.2 使用关联数组优化处理
统计单词频率的高级方法:
bash复制declare -A word_count
while IFS= read -r line; do
for word in $line; do
((word_count["$word"]++))
done
done < document.txt
for word in "${!word_count[@]}"; do
printf "%s: %d\n" "$word" "${word_count[$word]}"
done
6. 调试与错误处理艺术
6.1 调试技巧大全
使用set命令灵活调试:
bash复制#!/bin/bash
set -x # 开启命令打印
# 脚本内容...
set +x # 关闭命令打印
自定义调试函数:
bash复制debug() {
[ "$verbose" ] && echo "[DEBUG] $@" >&2
}
debug "Starting processing of $input"
6.2 健壮的错误处理
使用trap捕获信号:
bash复制cleanup() {
echo "Cleaning up temp files..."
rm -f "$tempfile"
}
trap cleanup EXIT INT TERM
tempfile=$(mktemp)
# 脚本主要内容...
检查命令可用性:
bash复制check_deps() {
for cmd in awk sed grep; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: $cmd not found" >&2
exit 1
fi
done
}
7. 跨平台兼容性实践
7.1 shebang的兼容写法
适应不同环境的shebang:
bash复制#!/usr/bin/env bash
7.2 避免bash特有语法
如果需要兼容纯sh环境:
bash复制# 使用test代替[[ ]]
if test -f "$file"; then
echo "File exists"
fi
# 使用case代替高级模式匹配
case "$OSTYPE" in
linux*) echo "Linux" ;;
darwin*) echo "MacOS" ;;
*) echo "Other" ;;
esac
8. 我的Shell工具箱推荐
8.1 必备辅助工具
- shellcheck - 静态分析工具:
bash复制# 安装
apt-get install shellcheck # Debian/Ubuntu
brew install shellcheck # MacOS
# 使用
shellcheck myscript.sh
- bat - 更好的cat替代品:
bash复制bat --line-range 50:100 --theme=TwoDark access.log
8.2 实用函数库
日志记录函数:
bash复制log() {
local level="$1"
local message="$2"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] [$level] $message" >> "$logfile"
}
log "INFO" "Script started"
安全路径处理:
bash复制normalize_path() {
local path="$1"
# 转换为绝对路径
if [ "${path:0:1}" != "/" ]; then
path="$PWD/$path"
fi
# 去除多余的/和./
echo "$path" | sed 's#/\+#/#g; s#/\./#/#g; s#/$##'
}
这份笔记中的技巧都是我在实际运维工作中反复验证过的,特别是处理生产环境问题时,健壮性和安全性比花哨的功能更重要。建议读者从简单的脚本开始,逐步积累自己的工具库,最终形成一套高效的Shell工作流。
