Linux 文本處理三劍客:grep、awk、sed 全面學習筆記
一站式掌握文本處理三大件:從入門到生產,再到性能與坑位。
目錄
-
快速對比總覽(何時用誰)
-
正則與編碼小抄(BRE/ERE/PCRE、大小寫與多行)
-
grep—— 搜索與過濾- 用法速覽與退出碼
- 參數總表(GNU 常見 + 兼容性提示)
- 高頻場景與示例
-
awk—— 結構化提取、計算與格式化- 語言模型(pattern { action })
- 命令行參數、內置變量、內置函數
- 常見場景與腳本范式
-
sed—— 流編輯(替換、刪除、插入、分支、多行)- 命令行參數與腳本語法
- 地址選擇與編輯命令全集
- 高頻場景與示例
-
組合技:
grep | awk | sed管道實踐 -
兼容性與性能優化(GNU vs. BSD/macOS、LC_ALL、遞歸、并行)
-
練習題與參考答案思路
1) 快速對比總覽
| 工具 | 核心定位 | 強項 | 適合用來 | 不太適合 |
|---|---|---|---|---|
| grep | 搜索/過濾 行 | 高速正則匹配、遞歸過濾、上下文顯示 | 在海量文本中找出匹配行、統計匹配數量、標色顯示 | 跨行結構化處理、復雜格式化輸出 |
| awk | 行→字段 的結構化處理 | 字段切分、聚合計算、條件篩選、格式化輸出 | CSV/TSV/日志字段統計、報表、輕腳本 | 大規模跨行替換(交給 sed)、復雜正則構建(可配合 grep) |
| sed | 流式編輯 | 原地(-i)替換、批量規則、地址選擇、跨行編輯 | 批量改配置、清洗文本、多條替換規則 | 復雜統計/聚合(交給 awk) |
選擇口訣:找誰?grep;算誰?awk;改誰?sed。
2) 正則與編碼小抄
- BRE(Basic):傳統基礎正則(默認
grep -G、sed),如\{m,n\}需要反斜杠。 - ERE(Extended):擴展正則(
grep -E、sed -E/-r、awk默認),+ ? | () {}無需反斜杠。 - PCRE:Perl 正則(
grep -P,有些平臺未編譯開啟),支持前后查找等高級特性。 - 大小寫:
-i忽略大小寫。更快匹配可設LC_ALL=C(ASCII 語義、提升速度)。 - 多行:
grep -z結合-P的(?s)可跨“行”(以 NUL 為分隔);sed用N/H/G;awk用自定義RS。
兼容提示:macOS 的
sed是 BSD 版,無-r,用-E;grep -P可能不可用。
3) grep —— 搜索與過濾
3.1 用法與退出碼
grep [OPTIONS] PATTERN [FILE...]
# 或:
grep [OPTIONS] -e PATTERN ...
- 退出碼:
0=找到匹配;1=未匹配;2=錯誤(如文件不存在、正則錯誤)。
3.2 參數總表(GNU grep 常見)
? 為最常用;?? 為兼容性或小眾;?? 為文件系統相關;?? 為顯示控制
| 選項 | 含義 | 備注 |
|---|---|---|
? -e PATTERN |
指定匹配表達式,可多次 | 避免與以 - 開頭的模式沖突 |
? -f FILE |
從文件讀取模式(每行一個) | 適合維護黑/白名單 |
? -i, --ignore-case |
忽略大小寫 | |
? -v, --invert-match |
取反(輸出不匹配的行) | 負過濾 |
? -w, --word-regexp |
整詞匹配 | 以非字母數字邊界界定 |
? -x, --line-regexp |
整行匹配 | 模式需匹配整行 |
? -o, --only-matching |
只打印匹配片段 | 提取值利器 |
? -m NUM, --max-count=NUM |
每文件匹配到 NUM 行后停止 | 搭配 -l 很快 |
? -q, --quiet |
靜默(只看退出碼) | 管道/條件判斷非常有用 |
? -s, --no-messages |
靜默錯誤信息 | 與腳本搭配 |
? -n, --line-number |
顯示行號 | |
? -H, --with-filename |
始終顯示文件名 | 默認多文件自動顯示 |
? -h, --no-filename |
隱藏文件名 | 合并輸出時干凈 |
? -c, --count |
每文件只輸出匹配計數 | 常與 sort -nr 組合 |
? -l, --files-with-matches |
僅輸出有匹配的文件名 | 反之 -L |
? -L, --files-without-match |
僅輸出無匹配的文件名 | |
? -A N, --after-context=N |
顯示匹配后 N 行 | |
? -B N, --before-context=N |
顯示匹配前 N 行 | |
? -C N, --context=N |
顯示前后 N 行 | |
?? --color[=WHEN] |
高亮匹配 | auto/always/never |
?? -E, --extended-regexp |
使用 ERE | 等同歷史 egrep |
?? -F, --fixed-strings |
字面量匹配(不當正則) | 等同歷史 fgrep,最快 |
?? -G, --basic-regexp |
使用 BRE(默認) | |
?? -P, --perl-regexp |
PCRE(前后查找等) | 某些系統不可用 |
?? -r, --recursive |
遞歸讀取目錄 | 不跟隨符號鏈接 |
?? -R, --dereference-recursive |
遞歸并跟隨符號鏈接 | |
?? -d ACTION |
目錄處理:read/recurse/skip |
與 -r 控制精細行為 |
?? --exclude=GLOB |
排除匹配文件 | 遞歸時常用 |
?? --include=GLOB |
僅包含匹配文件 | 遞歸時常用 |
?? --exclude-dir=GLOB |
排除目錄 | 遞歸時常用 |
?? --binary-files=TYPE |
binary/text/without-match |
-a=text,-I=without-match |
?? -a, --text |
二進制按文本處理 | |
?? -I |
忽略二進制文件 | 不報“Binary file matches” |
?? --line-buffered |
行緩沖輸出 | 低延遲管道 |
?? -b, --byte-offset |
顯示字節偏移 | 索引定位 |
?? -Z, --null |
文件名后跟 NUL 分隔 | 供 xargs -0 使用 |
?? -z, --null-data |
以 NUL 分隔輸入“行” | 跨行匹配技巧 |
BSD/macOS
grep不完全等同:--exclude-dir等選項可能缺失,可改用find ... -exec grep ...組合。
3.3 高頻場景與示例
(1) 遞歸查找關鍵字并顯示上下文
grep -RIn --color -C2 "TODO|FIXME" src/
(2) 僅統計各文件中 ERROR 次數
grep -Rhc "^ERROR" logs/ | paste -d: <(find logs -type f | sort) - | sort -t: -k2,2nr | head
(3) 提取匹配片段(只要值)
# 從日志中提取 IPv4
grep -RoE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" /var/log | cut -d: -f2 | sort -u
(4) PCRE 跨“行”抓塊(如 BEGIN..END)
# -z 將換行視作普通字符;(?s) 讓 . 匹配換行
grep -Pzo '(?s)BEGIN.*?END' big.txt | tr '\0' '\n'
(5) 快速判斷并按退出碼處理
if grep -q "CRITICAL" app.log; then
echo "發現致命錯誤,立即告警!"
fi
4) awk —— 結構化提取、計算與格式化
4.1 語言模型與基本用法
awk 'pattern { action }' file
# pattern 省略=>匹配所有行;action 省略=>打印當前行
示例:統計第 3 列之和(逗號分隔)
awk -F, '{sum+=$3} END{print sum}' data.csv
4.2 常用命令行參數
| 選項 | 含義 | 備注 |
|---|---|---|
-F FS |
指定輸入分隔符(字段分隔) | 如 -F, 處理 CSV |
-v var=val |
預先設置變量 | 如 -v OFS="," |
-f prog.awk |
從文件讀取程序 | 便于復用與維護 |
-e 'program' |
直接指定程序片段 | 可多次疊加 |
-- |
結束選項處理 | 后續按參數傳給程序 |
GNU awk(gawk)常見擴展選項(不同版本略有差異):
--posix(嚴格 POSIX 語義)/--traditional(傳統兼容)/--lint[=fatal](提示可疑用法)/--sandbox(禁用system()/文件 IO)/--debug(內置調試器)/--profile[=FILE](生成剖析信息)/--dump-variables[=FILE](導出全局變量與函數表)/--pretty-print[=FILE](美化輸出程序)。
4.3 內置變量(高頻)
| 變量 | 作用 | 示例 |
|---|---|---|
$0 |
當前整行 | print $0 |
$1..$NF |
第 N 個字段 | print $1,$3 |
NF |
當前行字段數 | if (NF<5) print |
NR |
讀到的總行號(全局) | NR==1{print "header"} |
FNR |
當前文件內行號 | 多文件時常用 |
FS |
輸入分隔符 | 默認空白;可在 BEGIN 設置 |
OFS |
輸出分隔符 | 默認空格 |
RS |
記錄分隔符(行分隔) | 可設置為空行或自定義分隔 |
ORS |
輸出記錄分隔符 | 默認換行 |
FILENAME |
當前文件名 | |
ARGC/ARGV |
參數個數/數組 | 腳本參數處理 |
ENVIRON |
環境變量數組 | ENVIRON["HOME"] |
IGNORECASE |
忽略大小寫(gawk) | IGNORECASE=1 |
4.4 內置函數小抄
- 數字:
int()sqrt()rand()srand()atan2() - 字符串:
length()index(s,t)substr(s,i[,n])split(s,a[,fs])match(s,r)sub(r,s)gsub(r,s)gensub(r,s,how[,t])(gawk)tolower/ toupper - 數組(gawk):
asort(a[,d])排序到數組;asorti(a[,d])按鍵排序 - 時間(gawk):
systime()strftime(fmt[,ts])mktime() - IO/系統:
system(cmd)getlineclose()fflush()
4.5 高頻場景與示例
(1) 選擇列與重排格式
# 取第1、3列,并以逗號輸出
awk -F'\t' -vOFS=, '{print $1,$3}' input.tsv > out.csv
(2) 條件篩選 + 聚合
# 只統計狀態為 200 的字節數總和(NCSA 日志示例)
awk '$9==200 {sum+=$10} END{print sum}' access.log
(3) 分組聚合(按字段計數 TopN)
awk -F, '{cnt[$2]++} END{for(k in cnt) print cnt[k],k}' data.csv | sort -nr | head
(4) 使用正則匹配字段
awk -F: '$1 ~ /^(sys|daemon)/ {print $1,$3}' /etc/passwd
(5) 自定義記錄分隔符(跨行記錄)
# 以空行分隔記錄(如 RFC-style headers)
awk -v RS='' '{print NR, length($0)}' mail.txt
(6) 生成簡易報表(帶表頭、對齊)
awk -F, 'BEGIN{printf "%-20s %8s\n","City","Pop"}
{printf "%-20s %8d\n", $1, $2}' city.csv
5) sed —— 流編輯
5.1 命令行參數
| 選項 | 含義 | 備注 |
|---|---|---|
-n |
安靜模式(不自動打印) | 需要顯式 p 打印 |
-e 'script' |
添加一條腳本命令 | 可多次疊加 |
-f script.sed |
從文件讀取腳本 | 復雜場景推薦 |
-i[SUFFIX] |
原地修改(可備份后綴) | macOS 需 -i '' 無備份 |
-E / -r |
使用 ERE 擴展正則 | BSD/macOS 用 -E;GNU 兩者皆可 |
-s |
將每個文件視作獨立流 | 多文件時避免跨文件狀態影響 |
-u |
嘗試更少緩沖(兼容用途) | GNU sed 多為兼容占位 |
-z |
以 NUL 分隔記錄 | 處理含換行的“記錄” |
-l N |
l 命令換行寬度 |
sed -n 'l' 可顯示不可見字符 |
5.2 地址選擇(選中要處理的行)
- 單地址:
N(第 N 行)、$(最后一行)、/regex/(匹配行) - 范圍:
addr1,addr2(如10,20//start/,/end//5,$) - 步進:
first~step(如1~2選奇數行) - 取反:
addr!cmd(對不匹配的行執行 cmd)
5.3 編輯命令全集(常用)
| 命令 | 作用 | 示例 |
|---|---|---|
s/regex/repl/flags |
替換 | s/foo/bar/g 全局;s/a/A/2 第二處;I 忽略大小寫 |
p |
打印當前模式空間 | 常與 -n 配合只打印命中行 |
d |
刪除當前行(讀下一行) | 過濾 |
D |
刪除第一個換行前的內容并立即重新開始 | 多行編輯利器 |
q [CODE] |
退出 sed |
加速:匹配到即退出 |
Q [CODE] |
立即退出,不打印模式空間 | |
a\ text |
在后追加文本 | a\new line |
i\ text |
在前插入文本 | |
c\ text |
替換選擇的整行 | |
y/set1/set2/ |
字符集替換(逐字符) | ROT13 等 |
n |
打印(若非 -n)并讀下一行 | 與條件流結合 |
N |
將下一行追加到模式空間(加入換行) | 跨行編輯 |
h/H |
覆蓋/追加到保持空間 | 雙緩沖技巧 |
g/G |
從保持空間覆蓋/追加到模式空間 | |
x |
交換保持空間與模式空間 | |
= |
打印當前行號 | |
r file |
讀文件內容并插入(在當前行后) | |
w file |
將當前行寫入文件 | |
: label / b label |
創建標簽 / 跳轉 | t label 為“若有替換則跳轉” |
l |
可視化打印(轉義不可見字符) | 與 -l 結合換行寬度 |
\在腳本文件中用于續行;交互命令中a\/i\/c\后通常需換行輸入正文。
5.4 高頻場景與示例
(1) 原地批量替換(帶備份)
# GNU/Linux:備份為 .bak;macOS:-i '' 表示不留備份
gnu_sed: sed -i.bak 's/old/new/g' *.conf
mac_sed: sed -i '' 's/old/new/g' *.conf
(2) 只替換匹配行的第一個 IP 為 [MASK]
sed '/ERROR/ s/\b\([0-9]{1,3}\.){3}[0-9]{1,3}\b/[MASK]/' app.log
(3) 刪除區塊(從 START 到 END)
sed '/^# START/,/^# END/d' config.ini
(4) 跨行合并:把以反斜杠續行的兩行拼成一行
# 將結尾為 \ 的行與下一行合并(去掉續行符)
sed -e ':a' -e '/\\$/ N; s/\\\n//; ta' file
(5) 僅打印包含 foo 的行的下一行
sed -n '/foo/{n;p}' file
(6) 復雜腳本文件示例(多規則)
# clean.sed
# 1) 去掉注釋與空行
/^[[:space:]]*#/d
/^[[:space:]]*$/d
# 2) 規范等號兩側空白
s/[[:space:]]*=[[:space:]]*/ = /g
# 3) key 全部小寫
s/^\([A-Za-z_][A-Za-z0-9_]*\)/\L\1/
運行:sed -f clean.sed input.conf > output.conf
6) 組合技:管道與分工
(1) 先篩后算
# 統計 5xx 狀態的請求體字節和
grep -E "\s5[0-9]{2}\s" access.log | awk '{sum+=$10} END{print sum}'
(2) 先改再算
# 將大小寫不敏感的 ERROR/WARN 統一為大寫再按級別計數
sed -E 's/(error|warn)/\U\1/g' app.log | awk '{cnt[$1]++} END{for(k in cnt)print k,cnt[k]}'
(3) 結構化提取 + 僅值輸出
# 提取配置中所有端口號(去重、排序)
grep -RhoE '\bport[[:space:]]*=[[:space:]]*[0-9]+\b' conf/ |
sed -E 's/.*=\s*([0-9]+)/\1/' |
sort -n | uniq
7) 兼容性與性能優化
-
GNU vs. BSD/macOS:
sed -i:GNU 可省后綴,macOS 需-i ''才不留備份。sed -r:GNU 可用,macOS 無此選項,用-E。grep -P:PCRE 在部分系統未編譯;可用perl -ne 'print if /.../'代替。- 一些
--exclude*選項在 BSDgrep缺失,用find ... -exec組合。
-
速度優化:
- 確定是字面量匹配:
grep -F更快。 - 降低本地化開銷:
LC_ALL=C可顯著加速純 ASCII 文本處理。 - 大目錄遞歸:用
ripgrep (rg)可更快;或xargs -P并行。 awk中減少管道與system()調用;匯總放在END{}。
- 確定是字面量匹配:
-
健壯性:
- 處理“奇怪文件名”用 NUL 分隔:
grep -Z、xargs -0、find -print0。 - 正則含
{}在 BRE 需轉義;在 ERE 則不需。 - 批量改文件建議先備份或用
git追蹤。
- 處理“奇怪文件名”用 NUL 分隔:
8) 練習題(附思路)
-
統計 NCSA 日志中各 IP 命中數 Top 10
思路:awk '{cnt[$1]++} END{for(k in cnt) print cnt[k],k}' | sort -nr | head -
把
.env文件里KEY=value的 value 去掉兩端空白并小寫
思路:sed -E 's/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/\1=\L\2/' .env -
在源碼中查找 TODO,并顯示文件名、行號與前后 1 行上下文
思路:grep -RIn -C1 'TODO' src/ -
從 CSV 第 2 列提取域名,統計不同后綴 .com/.net/.org 數量
思路:awk -F, '{split($2,a,"."); t=a[length(a)]; cnt[t]++} END{for(k in cnt)print k,cnt[k]}' file.csv -
合并以反斜杠續行的配置,刪除注釋與空行
思路:用sed的N; s/\\\n//合并,再用地址與正則刪除注釋/空白。
附:常見錯誤排查
sed: RE error: illegal byte sequence:設置LC_ALL=C或統一輸入編碼。grep: binary file matches:加-a或-I。awk: field separator被正則特殊含義影響:用字符類或轉義,如-F'[|]'。- macOS
sed -i報錯:需-i ''。
溫馨提示:不同發行版/版本參數可能略有差異,以
man grep/man sed/man awk或--help為準。本文覆蓋 GNU 常見參數與實踐套路,滿足日常到生產的大多數需求。

浙公網安備 33010602011771號