文本处理三剑客¶
📌 学习时间:4-5天 📌 难度级别:⭐⭐⭐ 中级 📌 前置知识:文件与目录管理、基础正则表达式
📚 章节概述¶
grep、sed、awk 被称为 Linux 文本处理「三剑客」,是 Shell 编程和日常运维中最强大的工具。本章将深入讲解正则表达式、三剑客的完整用法,以及 sort/uniq/cut/paste/tr/wc 等辅助工具,配合大量日志分析和数据提取的实战案例。
🎯 学习目标¶
- 精通正则表达式(基础正则 + 扩展正则)
- 熟练使用 grep 进行文本搜索
- 掌握 sed 流编辑器的完整用法
- 掌握 awk 模式匹配与数据处理
- 熟练使用 sort/uniq/cut/paste/tr/wc 等工具
- 深入理解管道和重定向机制
- 能独立完成日志分析和数据提取任务
📖 1. 正则表达式详解¶
1.1 基础正则表达式(BRE)¶
Bash
# 字符匹配
. # 匹配任意单个字符
[abc] # 匹配 a、b 或 c 中的任一个
[a-z] # 匹配 a 到 z 中的任一个
[0-9] # 匹配数字
[^abc] # 匹配非 a、b、c 的任一字符
[^0-9] # 匹配非数字字符
# 锚定
^ # 匹配行首
$ # 匹配行尾
^$ # 匹配空行
\b # 匹配单词边界
\< # 匹配单词开头
\> # 匹配单词结尾
# 量词(BRE 中需要转义)
* # 前一个字符出现 0 次或多次
\+ # 前一个字符出现 1 次或多次
\? # 前一个字符出现 0 次或 1 次
\{n\} # 前一个字符出现 n 次
\{n,\} # 前一个字符出现至少 n 次
\{n,m\} # 前一个字符出现 n 到 m 次
# 分组与反向引用
\(pattern\) # 分组
\1 \2 # 反向引用第 1、2 个分组
1.2 扩展正则表达式(ERE)¶
Bash
# ERE 中量词不需要转义(使用 grep -E 或 egrep)
+ # 1次或多次
? # 0次或1次
{n} # 恰好n次
{n,} # 至少n次
{n,m} # n到m次
# 交替
| # 或(cat|dog 匹配 cat 或 dog)
# 分组
(pattern) # 分组(不需要转义)
\1 # 反向引用
# POSIX 字符类
[:alpha:] # 字母 [a-zA-Z]
[:digit:] # 数字 [0-9]
[:alnum:] # 字母和数字
[:space:] # 空白字符
[:upper:] # 大写字母
[:lower:] # 小写字母
[:punct:] # 标点符号
# 使用方式
grep '[[:digit:]]' file.txt # 包含数字的行
grep '[[:upper:]][[:lower:]]' f # 大写后跟小写
1.3 正则表达式实例¶
Bash
# 匹配 IP 地址(简化版)
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' file
# 匹配邮箱
grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file
# 匹配手机号(中国大陆)
grep -E '1[3-9][0-9]{9}' file
# 匹配日期 (YYYY-MM-DD)
grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' file
# 匹配 URL
grep -E 'https?://[a-zA-Z0-9./?=_-]+' file
# 匹配空行
grep '^$' file
# 匹配注释行(# 开头,允许前导空格)
grep -E '^\s*#' file
# 匹配非空非注释行
grep -vE '^\s*(#|$)' file
📖 2. grep — 文本搜索¶
2.1 基本用法¶
Bash
# 基本语法:grep [选项] 模式 文件
# 基本搜索
grep "error" /var/log/syslog # 搜索包含 error 的行
grep "error" file1 file2 file3 # 在多个文件中搜索
grep "error" /var/log/*.log # 通配符搜索
# 常用选项
grep -i "error" file # 忽略大小写
grep -v "debug" file # 反向匹配(排除包含 debug 的行)
grep -n "error" file # 显示行号
grep -c "error" file # 只显示匹配的行数
grep -l "error" /var/log/*.log # 只显示文件名
grep -L "error" /var/log/*.log # 显示不匹配的文件名
grep -w "error" file # 全词匹配(不匹配 errors)
grep -x "exact line" file # 整行匹配
grep -r "error" /var/log/ # 递归搜索目录
grep -rn "TODO" ./src/ # 递归搜索 + 行号
# 上下文显示
grep -A 3 "error" file # 显示匹配行后3行(After)
grep -B 3 "error" file # 显示匹配行前3行(Before)
grep -C 3 "error" file # 显示匹配行前后3行(Context)
# 使用正则表达式
grep "^root" /etc/passwd # 以 root 开头的行
grep "bash$" /etc/passwd # 以 bash 结尾的行
grep -E "error|warning|critical" file # 扩展正则(多个模式)
grep -P "\d{3}-\d{4}" file # Perl 正则表达式
2.2 grep 进阶技巧¶
Bash
# 从标准输入搜索
ps aux | grep nginx # 在进程列表中搜索
ps aux | grep "[n]ginx" # 排除 grep 自身
# 多模式搜索
grep -e "error" -e "warning" file # 多个 -e
grep -f patterns.txt file # 从文件读取模式
# 统计和排序
grep -c "error" /var/log/*.log | sort -t: -k2 -rn # 各文件错误数排序
# 只输出匹配部分
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' access.log
# 搜索二进制文件
grep -a "string" binary_file # 将二进制作为文本处理
# 搜索压缩文件
zgrep "error" file.gz # 搜索 gzip 压缩文件
bzgrep "error" file.bz2 # 搜索 bzip2 压缩文件
📖 3. sed — 流编辑器¶
3.1 基本用法¶
Bash
# 基本语法:sed [选项] '命令' 文件
# 替换(最常用的操作)
sed 's/old/new/' file # 替换每行第一个匹配
sed 's/old/new/g' file # 全局替换(每行所有匹配)
sed 's/old/new/2' file # 替换每行第2个匹配
sed 's/old/new/gi' file # 全局替换 + 忽略大小写
# 选项
sed -n 's/old/new/p' file # 只打印替换了的行
sed -i 's/old/new/g' file # 直接修改文件(就地编辑)
sed -i.bak 's/old/new/g' file # 修改前备份为 file.bak
sed -e 's/a/b/' -e 's/c/d/' file # 多个编辑命令
# 使用不同的分隔符(当替换内容含 / 时很有用)
sed 's|/usr/local|/opt|g' file # 用 | 作分隔符
sed 's#http://#https://#g' file # 用 # 作分隔符
3.2 地址与范围¶
Bash
# 行号地址
sed '3s/old/new/' file # 只替换第3行
sed '1,5s/old/new/' file # 替换第1到5行
sed '3,$s/old/new/' file # 从第3行到最后一行
sed '1~2s/old/new/' file # 从第1行开始每隔2行替换(奇数行)
# 正则地址
sed '/error/s/old/new/' file # 包含 error 的行中替换
sed '/^#/d' file # 删除以 # 开头的行(注释)
sed '/start/,/end/s/a/b/' file # 在 start 到 end 范围内替换
# 取反
sed '/^$/!s/^/ /' file # 非空行添加缩进
3.3 常用操作¶
Bash
# 删除
sed 'd' file # 删除所有行
sed '3d' file # 删除第3行
sed '1,5d' file # 删除第1到5行
sed '/^$/d' file # 删除空行
sed '/^#/d' file # 删除注释行
sed '/^$/d;/^#/d' file # 删除空行和注释行
# 插入和追加
sed '3i\新插入的行' file # 在第3行前插入(insert)
sed '3a\新追加的行' file # 在第3行后追加(append)
sed '1i\#!/bin/bash' script.sh # 在文件开头插入
# 替换整行
sed '3c\完全替换的新内容' file # 替换第3行
# 打印
sed -n '5p' file # 只打印第5行
sed -n '1,10p' file # 打印第1到10行
sed -n '/error/p' file # 打印匹配行(类似 grep)
sed -n '5,10p' file # 类似 head+tail
# 转换
sed 'y/abc/ABC/' file # 逐字符转换(a→A, b→B, c→C)
# 多行操作
sed 'N;s/\n/ /' file # 将两行合并为一行
3.4 sed 高级技巧¶
Bash
# 反向引用
sed 's/\(.*\):\(.*\)/\2:\1/' file # 交换:前后内容
sed -E 's/([0-9]+)-([0-9]+)/\2-\1/' file # 交换数字
# 添加行号
sed = file | sed 'N;s/\n/\t/'
# 在匹配行后添加内容
sed '/pattern/a\添加的新行' file
# 读取和写入文件
sed '/MARKER/r input.txt' file # 在 MARKER 后插入文件内容
sed -n '/error/w errors.txt' file # 将匹配行写入文件
# 处理配置文件
# 修改配置项
sed -i 's/^port=.*/port=8080/' config.conf
sed -i 's/^#\(allow_remote\)/\1/' config.conf # 取消注释
# Hold Space 用法(高级)
# sed 有两个缓冲区:Pattern Space(处理区)和 Hold Space(保留区)
# h: pattern → hold(覆盖)
# H: pattern → hold(追加)
# g: hold → pattern(覆盖)
# G: hold → pattern(追加)
# x: 交换两个缓冲区
# 反转文件行序(类似 tac)
sed -n '1!G;h;$p' file
# 删除连续重复行(类似 uniq)
sed '$!N;/^\(.*\)\n\1$/!P;D' file
📖 4. awk — 模式匹配与数据处理¶
4.1 基本概念¶
Bash
# awk 是一门完整的编程语言,擅长处理结构化文本数据
# 基本语法:awk 'pattern {action}' file
# awk 逐行读取输入,自动将每行分割成字段
# 字段变量
# $0 整行内容
# $1 第一个字段
# $2 第二个字段
# $NF 最后一个字段
# NR 当前行号(Number of Records)
# NF 当前行字段数(Number of Fields)
# FS 字段分隔符(Field Separator,默认空格/Tab)
# OFS 输出字段分隔符(Output Field Separator)
# RS 记录分隔符(Record Separator,默认换行)
# ORS 输出记录分隔符
# 示例数据:employees.txt
# Alice Engineering 85000
# Bob Marketing 72000
# Charlie Engineering 92000
# Diana Marketing 68000
# Eve Engineering 78000
4.2 基本用法¶
Bash
# 打印特定字段
awk '{print $1}' employees.txt # 打印第一列(名字)
awk '{print $1, $3}' employees.txt # 打印第1和第3列
awk '{print $NF}' employees.txt # 打印最后一列
awk '{print NR, $0}' employees.txt # 打印行号和整行
# 格式化输出
awk '{printf "%-10s %-15s %d\n", $1, $2, $3}' employees.txt
# 指定分隔符
awk -F: '{print $1, $7}' /etc/passwd # 以 : 分隔
awk -F, '{print $1, $2}' data.csv # 处理 CSV
awk 'BEGIN{FS=":"} {print $1}' /etc/passwd # BEGIN 块中设置
# 设置输出分隔符
awk -F: 'BEGIN{OFS=","} {print $1,$3,$7}' /etc/passwd
4.3 模式匹配¶
Bash
# 正则模式
awk '/Engineering/' employees.txt # 包含 Engineering 的行
awk '!/Marketing/' employees.txt # 不包含 Marketing 的行
awk '/^A/' employees.txt # A 开头的行
# 表达式模式
awk '$3 > 80000' employees.txt # 薪资大于80000
awk '$3 > 80000 {print $1, $3}' employees.txt # 筛选并打印
awk '$2 == "Engineering"' employees.txt # 部门是 Engineering
awk 'NR >= 2 && NR <= 4' employees.txt # 第2到4行
# 范围模式
awk '/Bob/,/Diana/' employees.txt # 从 Bob 到 Diana 的行
# BEGIN 和 END
awk 'BEGIN{print "=== 员工报表 ==="} {print $0} END{print "=== 共 "NR" 人 ==="}' employees.txt
# 组合条件
awk '$2 == "Engineering" && $3 > 80000' employees.txt
awk '$3 > 90000 || $3 < 70000' employees.txt
4.4 编程功能¶
Bash
# 变量
awk '{sum += $3} END{print "总薪资:", sum}' employees.txt
awk '{sum += $3; count++} END{print "平均薪资:", sum/count}' employees.txt
# 条件语句
awk '{
if ($3 > 80000)
print $1, "高薪"
else if ($3 > 70000)
print $1, "中等"
else
print $1, "一般"
}' employees.txt
# 循环
awk '{for(i=1; i<=NF; i++) print NR, i, $i}' employees.txt
# 数组(关联数组)
# 统计每个部门的人数
awk '{dept[$2]++} END{for(d in dept) print d, dept[d]}' employees.txt
# 统计每个部门的总薪资
awk '{dept[$2] += $3} END{for(d in dept) printf "%-15s %d\n", d, dept[d]}' employees.txt
# 字符串函数
awk '{print length($1), $1}' employees.txt # 字符串长度
awk '{print toupper($1)}' employees.txt # 转大写
awk '{print tolower($2)}' employees.txt # 转小写
awk '{print substr($1, 1, 3)}' employees.txt # 子串
awk '{sub(/Engineering/, "Eng"); print}' employees.txt # 替换
awk '{gsub(/a/, "A"); print}' employees.txt # 全局替换
awk '{n = split($0, arr, " "); print n}' employees.txt # 分割
# 数学函数
awk 'BEGIN{print sin(1); print sqrt(144); print int(3.7)}'
4.5 awk 实战范例¶
Bash
# 处理 /etc/passwd
# 打印所有普通用户(UID>=1000)
awk -F: '$3 >= 1000 {print $1, $3, $7}' /etc/passwd
# 统计每种 Shell 的用户数
awk -F: '{shell[$NF]++} END{for(s in shell) print s, shell[s]}' /etc/passwd
# 处理 CSV 文件
# data.csv:
# Name,Age,City,Score
# Alice,25,Beijing,92
# Bob,30,Shanghai,88
# Charlie,28,Guangzhou,95
awk -F, 'NR>1 && $4>90 {print $1, $4}' data.csv # 分数>90的
# 处理 Nginx access.log
# 统计访问量 Top 10 IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 统计 HTTP 状态码分布
awk '{status[$9]++} END{for(s in status) print s, status[s]}' access.log
# 统计每小时请求量
# -F'[/:]' 分割后:$1=IP等 $2=月 $3=年 $4=小时 $5=分钟
awk -F'[/:]' '{hour=$4; count[hour]++} END{for(h in count) print h, count[h]}' access.log
# 找出响应时间最长的请求
awk '{if($NF > max) {max=$NF; line=$0}} END{print max, line}' access.log
# 多文件处理
awk 'FNR==1{print "--- " FILENAME " ---"} {print}' file1 file2
# awk 脚本文件
# script.awk:
# BEGIN { FS=","; OFS="\t"; print "Name", "Score" }
# NR > 1 && $4 > 90 { print $1, $4 }
# END { print "---Done---" }
awk -f script.awk data.csv
📖 5. 辅助文本工具¶
5.1 sort — 排序¶
Bash
sort file.txt # 字母排序
sort -n file.txt # 数值排序
sort -r file.txt # 逆序
sort -k2 file.txt # 按第2列排序
sort -k3 -n file.txt # 按第3列数值排序
sort -t: -k3 -n /etc/passwd # 指定分隔符排序
sort -u file.txt # 排序并去重
sort -h file.txt # 人类可读数字排序(1K, 2M, 3G)
sort -R file.txt # 随机排序
sort -k2,2 -k3,3n file.txt # 多键排序(先按第2列,再按第3列数值)
sort -s -k2 file.txt # 稳定排序
5.2 uniq — 去重¶
Bash
# 注意:uniq 只能去除相邻的重复行,通常需要先 sort
sort file.txt | uniq # 去除重复行
sort file.txt | uniq -c # 显示重复次数
sort file.txt | uniq -d # 只显示重复的行
sort file.txt | uniq -u # 只显示不重复的行
sort file.txt | uniq -ci # 忽略大小写计数
# 实用组合
# 统计词频
cat file | tr ' ' '\n' | sort | uniq -c | sort -rn | head -10
5.3 cut — 列提取¶
Bash
cut -d: -f1 /etc/passwd # 以:分隔,取第1列
cut -d: -f1,3 /etc/passwd # 取第1和第3列
cut -d: -f1-3 /etc/passwd # 取第1到第3列
cut -c1-10 file.txt # 取每行第1到10个字符
cut -d',' -f2 data.csv # CSV 取第2列
cut --complement -d: -f2 file # 取除了第2列以外的所有列
5.4 paste — 列合并¶
Bash
paste file1 file2 # 横向合并(Tab 分隔)
paste -d, file1 file2 # 以逗号分隔合并
paste -s file.txt # 将列转为行
# 实用示例
# 将单列转为3列
cat list.txt | paste - - - # 每3个一行
5.5 tr — 字符转换¶
Bash
# 字符替换
echo "hello" | tr 'a-z' 'A-Z' # 转大写: HELLO
echo "HELLO" | tr 'A-Z' 'a-z' # 转小写: hello
echo "hello" | tr 'el' 'ip' # e→i, l→p: hippo
# 删除字符
echo "hello 123 world" | tr -d '0-9' # 删除数字
echo "hello world" | tr -d ' ' # 删除空格
cat file | tr -d '\r' # 删除 Windows 换行符(\r)
# 压缩重复字符
echo "aabbcc" | tr -s 'a-z' # abc(每种字符只保留一个)
echo "hello world" | tr -s ' ' # hello world(压缩空格)
# 字符集补集
echo "hello 123" | tr -cd '0-9\n' # 只保留数字: 123
5.6 wc — 统计¶
Bash
wc file.txt # 行数 单词数 字节数
wc -l file.txt # 行数
wc -w file.txt # 单词数
wc -c file.txt # 字节数
wc -m file.txt # 字符数
wc -L file.txt # 最长行的长度
# 统计目录中文件数
ls -1 | wc -l
# 统计代码行数
find . -name "*.py" -exec cat {} + | wc -l
📖 6. 管道与重定向¶
6.1 重定向¶
Bash
# 标准文件描述符
# 0 = stdin(标准输入)
# 1 = stdout(标准输出)
# 2 = stderr(标准错误)
# 输出重定向
command > file # 标准输出写入文件(覆盖)
command >> file # 标准输出追加到文件
command 2> file # 标准错误写入文件
command 2>> file # 标准错误追加到文件
command > file 2>&1 # 标准输出和错误都写入文件
command &> file # 同上(Bash 简写)
command > out.log 2> err.log # 分别重定向
# 输入重定向
command < file # 从文件读取输入
command << EOF # Here Document
line1
line2
EOF
command <<< "string" # Here String
# /dev/null — 黑洞设备
command > /dev/null # 丢弃标准输出
command 2> /dev/null # 丢弃标准错误
command > /dev/null 2>&1 # 丢弃所有输出
6.2 管道¶
Bash
# 管道将前一个命令的标准输出作为后一个命令的标准输入
command1 | command2 | command3
# 经典组合
cat /etc/passwd | grep "/bin/bash" | cut -d: -f1 # 找 bash 用户
ps aux | grep nginx | grep -v grep # 找 nginx 进程
du -sh /var/log/* | sort -rh | head -10 # 最大的日志文件
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# tee — 同时输出到屏幕和文件
command | tee output.txt # 看到输出,同时保存文件
command | tee -a output.txt # 追加模式
command 2>&1 | tee log.txt # 标准输出和错误都记录
# xargs — 将标准输入转为命令参数
find . -name "*.tmp" | xargs rm # 删除找到的文件
find . -name "*.py" | xargs grep "import" # 搜索 Python 文件
echo "file1 file2 file3" | xargs -n1 echo # 逐个执行
find . -name "*.jpg" | xargs -I{} cp {} /backup/ # 使用占位符
# 进程替换(Bash 特性)
diff <(ls dir1) <(ls dir2) # 比较两个目录的文件列表
comm <(sort file1) <(sort file2) # 比较两个排序后的文件
📖 7. 实战案例¶
案例1:Nginx 日志分析¶
Bash
# 假设日志格式:
# 192.168.1.100 - - [15/Jan/2024:10:30:45 +0800] "GET /api/users HTTP/1.1" 200 1234
# 1. 统计总请求量
wc -l access.log
# 2. 统计访问量 Top 10 IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 3. 统计 HTTP 状态码分布
awk '{print $9}' access.log | sort | uniq -c | sort -rn
# 4. 统计最频繁的请求 URL
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -10
# 5. 统计每小时请求量
# -F'[:[]' 分割后:$1=IP等 $2=日期(15/Jan/2024) $3=小时
awk -F'[:[]' '{print $3}' access.log | sort | uniq -c
# 6. 查找 5xx 错误
awk '$9 ~ /^5/' access.log
# 7. 统计 404 请求
awk '$9 == "404" {print $7}' access.log | sort | uniq -c | sort -rn | head -10
# 8. 计算总带宽
awk '{sum += $10} END{printf "Total: %.2f MB\n", sum/1024/1024}' access.log
# 9. 找出慢请求(假设最后一列是响应时间)
awk '{if ($NF > 3) print}' access.log | head -20
# 10. 生成完整的日志分析报告
cat << 'SCRIPT' > analyze_log.sh
#!/bin/bash
LOG="${1:-access.log}"
echo "========== Nginx 日志分析报告 =========="
echo "文件: $LOG"
echo "总请求数: $(wc -l < "$LOG")"
echo ""
echo "--- Top 10 IP ---"
awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- HTTP 状态码分布 ---"
awk '{print $9}' "$LOG" | sort | uniq -c | sort -rn
echo ""
echo "--- Top 10 请求URL ---"
awk '{print $7}' "$LOG" | sort | uniq -c | sort -rn | head -10
echo "========================================"
SCRIPT
chmod +x analyze_log.sh
案例2:系统日志分析¶
Bash
# 查找登录失败的记录
grep "Failed password" /var/log/auth.log | \ # grep文本搜索:按模式匹配行
awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10 # $()命令替换:执行命令并获取输出
# 查找 SSH 暴力破解 IP
grep "Failed password" /var/log/auth.log | \
awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' | \
sort | uniq -c | sort -rn | head -20
# 统计今天不同级别的日志数量
grep "$(date +%b\ %d)" /var/log/syslog | \
grep -oE '(error|warning|info|debug|critical)' -i | \
tr 'A-Z' 'a-z' | sort | uniq -c | sort -rn
案例3:数据处理¶
Bash
# 处理 CSV 数据
# sales.csv:
# Date,Product,Quantity,Price
# 2024-01-01,Widget,100,9.99
# 2024-01-01,Gadget,50,19.99
# 2024-01-02,Widget,80,9.99
# 计算总销售额
awk -F, 'NR>1 {total += $3 * $4} END{printf "总销售额: $%.2f\n", total}' sales.csv
# 按产品统计销量
awk -F, 'NR>1 {qty[$2] += $3} END{for(p in qty) print p, qty[p]}' sales.csv # Shell for循环
# 按日期统计收入
awk -F, 'NR>1 {rev[$1] += $3*$4} END{for(d in rev) printf "%s: $%.2f\n", d, rev[d]}' sales.csv # awk文本处理:按列提取和格式化数据
# 提取特定信息并格式化
awk -F, 'NR>1 {printf "%-12s %-10s %5d $%8.2f\n", $1, $2, $3, $3*$4}' sales.csv
# 文本替换批处理
# 批量替换多个文件中的字符串
find . -name "*.conf" -exec sed -i 's/old_server/new_server/g' {} + # sed流编辑器:文本替换与转换
# 批量修改文件编码
find . -name "*.txt" -exec bash -c 'iconv -f GBK -t UTF-8 "$1" > "$1.utf8" && mv "$1.utf8" "$1"' _ {} \; # &&前一个成功才执行后一个;||前一个失败才执行
📖 8. 面试要点¶
高频面试题¶
Q1:grep、sed、awk 三者的区别和适用场景?
- grep:文本搜索(过滤),从输入中找出匹配行
- sed:流编辑,对文本进行替换、删除、插入等操作
- awk:文本处理编程语言,擅长分列处理和统计计算 简记:grep 负责找,sed 负责改,awk 负责算。
Q2:写一个命令统计 Nginx 日志中访问量 Top 10 的 IP
Q3:如何用 sed 删除文件中的空行和注释行?
Bash
sed '/^$/d;/^#/d' file # 删除空行和 # 注释行
sed '/^[[:space:]]*$/d;/^[[:space:]]*#/d' file # 包括只有空格的"空行"
Q4:解释 awk '{sum+=$NF} END{print sum}' 的含义
对每行取最后一个字段($NF)累加到变量 sum 中,处理完所有行后在 END 块中打印总和。
Q5:> 和 >> 的区别?2>&1 是什么意思?
>覆盖写入,>>追加写入。2>&1将标准错误(文件描述符2)重定向到标准输出(文件描述符1)所指向的地方。
🔧 练习题¶
基础练习¶
- 使用 grep 从
/etc/passwd中找出所有使用 bash 的用户 - 使用 sed 将文件中所有的
http://替换为https:// - 使用 awk 打印
/etc/passwd中 UID 大于1000的用户名和UID
进阶练习¶
- 统计一个 Python 源码文件中 import 了哪些模块
- 从一段日志中提取所有 IP 地址并去重统计
- 编写 awk 脚本处理 CSV 文件,输出格式化报表
综合实战¶
- 编写 Nginx 日志分析脚本(统计 IP、状态码、URL、带宽)
- 编写脚本分析
/var/log/auth.log统计 SSH 登录失败次数
✅ 自我检查¶
- 能写出常见的正则表达式(IP、邮箱、日期)
- 能用 grep 进行复杂的文本搜索
- 能用 sed 完成替换、删除、插入操作
- 能用 awk 进行分列处理和统计计算
- 熟练使用 sort/uniq/cut/tr/wc
- 理解管道和重定向的原理
- 能独立完成日志分析任务
上一章:02-文件与目录管理 下一章:04-用户与权限管理