[{"data":1,"prerenderedAt":1278},["ShallowReactive",2],{"doc-linux-grep-awk-sed":3,"same-cat-linux-grep-awk-sed":1277},{"id":4,"title":5,"author":6,"body":7,"category":1257,"date":1258,"description":1259,"draft":1260,"extension":1261,"meta":1262,"navigation":266,"path":1263,"seo":1264,"slug":1265,"stem":1266,"summary":1267,"tags":1271,"__hash__":1276},"docs\u002Fdocs\u002Flinux\u002Fgrep-awk-sed.md","grep \u002F awk \u002F sed 三大文本处理命令对比与示例","元析技术团队",{"type":8,"value":9,"toc":1229},"minimark",[10,14,18,21,96,104,114,117,121,125,225,228,341,344,374,376,380,403,406,463,470,473,512,575,607,646,669,672,699,701,705,720,726,732,735,760,767,780,818,821,901,904,925,958,960,964,971,1069,1072,1112,1114,1118,1122,1159,1163,1166,1200,1204,1215,1217,1220,1225],[11,12,13],"h2",{"id":13},"适用场景一句话划分",[15,16,17],"p",{},"校验环境:Debian 12 (GNU grep 3.11 \u002F GNU awk 5.2.1 \u002F GNU sed 4.9)",[15,19,20],{},"运维、后端、数据同学每天都在写的三条命令,分工非常明确:",[22,23,24,40],"table",{},[25,26,27],"thead",{},[28,29,30,34,37],"tr",{},[31,32,33],"th",{},"命令",[31,35,36],{},"作用",[31,38,39],{},"一句话判断",[41,42,43,62,79],"tbody",{},[28,44,45,52,59],{},[46,47,48],"td",{},[49,50,51],"strong",{},"grep",[46,53,54,55,58],{},"从输入中",[49,56,57],{},"挑行","(行过滤)",[46,60,61],{},"只想看到\u002F排除包含某字符串的行",[28,63,64,69,76],{},[46,65,66],{},[49,67,68],{},"awk",[46,70,71,72,75],{},"按",[49,73,74],{},"字段","切分、取值、统计",[46,77,78],{},"需要把每行按列切开,取第 3 列、求和、分组",[28,80,81,86,93],{},[46,82,83],{},[49,84,85],{},"sed",[46,87,88,89,92],{},"对每行",[49,90,91],{},"改内容","(替换\u002F删除\u002F插入)",[46,94,95],{},"想做全局替换、批量改配置、删某些行",[15,97,98,99,103],{},"下面用一份真实 Nginx access log(精简版)做完整示例。示例文件 ",[100,101,102],"code",{},"access.log",":",[105,106,111],"pre",{"className":107,"code":109,"language":110},[108],"language-text","192.168.1.10 - - [09\u002FAug\u002F2026:10:23:11 +0800] \"GET \u002Fdocs\u002Fgit\u002Fgit-stash HTTP\u002F1.1\" 200 3421 \"-\" \"Mozilla\u002F5.0\"\n10.0.0.5 - - [09\u002FAug\u002F2026:10:23:12 +0800] \"POST \u002Fapi\u002Flogin HTTP\u002F1.1\" 401 128 \"-\" \"curl\u002F8.5.0\"\n192.168.1.10 - - [09\u002FAug\u002F2026:10:23:13 +0800] \"GET \u002Fdocs\u002Flinux\u002Fgrep-awk-sed HTTP\u002F1.1\" 200 9820 \"-\" \"Mozilla\u002F5.0\"\n45.88.12.3 - - [09\u002FAug\u002F2026:10:23:14 +0800] \"GET \u002Fwp-login.php HTTP\u002F1.1\" 404 153 \"-\" \"python-requests\u002F2.31\"\n10.0.0.5 - - [09\u002FAug\u002F2026:10:23:15 +0800] \"POST \u002Fapi\u002Flogin HTTP\u002F1.1\" 200 512 \"-\" \"curl\u002F8.5.0\"\n","text",[100,112,109],{"__ignoreMap":113},"",[115,116],"hr",{},[11,118,120],{"id":119},"grep行过滤挑行","grep:行过滤(挑行)",[122,123,124],"h3",{"id":124},"最常用参数",[22,126,127,136],{},[25,128,129],{},[28,130,131,134],{},[31,132,133],{},"参数",[31,135,36],{},[41,137,138,148,161,175,185,195,205,215],{},[28,139,140,145],{},[46,141,142],{},[100,143,144],{},"-E",[46,146,147],{},"启用扩展正则(ERE),支持 `",[28,149,150,155],{},[46,151,152],{},[100,153,154],{},"-F",[46,156,71,157,160],{},[49,158,159],{},"固定字符串","匹配,不解析正则。匹配 IP、URL、路径时强烈推荐",[28,162,163,168],{},[46,164,165],{},[100,166,167],{},"-v",[46,169,170,171,174],{},"取反,输出",[49,172,173],{},"不匹配","的行",[28,176,177,182],{},[46,178,179],{},[100,180,181],{},"-n",[46,183,184],{},"显示行号",[28,186,187,192],{},[46,188,189],{},[100,190,191],{},"-c",[46,193,194],{},"只输出匹配行数",[28,196,197,202],{},[46,198,199],{},[100,200,201],{},"-i",[46,203,204],{},"忽略大小写",[28,206,207,212],{},[46,208,209],{},[100,210,211],{},"-r",[46,213,214],{},"递归搜目录下所有文件",[28,216,217,222],{},[46,218,219],{},[100,220,221],{},"-o",[46,223,224],{},"只输出匹配到的部分(不是整行)",[122,226,227],{"id":227},"真实示例",[105,229,233],{"className":230,"code":231,"language":232,"meta":113,"style":113},"language-bash shiki shiki-themes github-light github-dark","# 1. 看所有 4xx\u002F5xx 请求\ngrep -E '\" (4[0-9]{2}|5[0-9]{2}) ' access.log\n\n# 2. 看所有非爬虫(排除 UA 里带 curl 和 python-requests 的行)\ngrep -vE '\" (curl|python-requests)\u002F' access.log\n\n# 3. 按 IP 精确搜(用 -F 防止 . 被当成任意字符正则)\ngrep -F '10.0.0.5' access.log\n\n# 4. 数 200 状态码有多少条\ngrep -cE '\" 200 ' access.log\n# 输出:2\n","bash",[100,234,235,244,261,268,274,287,292,298,311,316,322,335],{"__ignoreMap":113},[236,237,240],"span",{"class":238,"line":239},"line",1,[236,241,243],{"class":242},"sJ8bj","# 1. 看所有 4xx\u002F5xx 请求\n",[236,245,247,250,254,258],{"class":238,"line":246},2,[236,248,51],{"class":249},"sScJk",[236,251,253],{"class":252},"sj4cs"," -E",[236,255,257],{"class":256},"sZZnC"," '\" (4[0-9]{2}|5[0-9]{2}) '",[236,259,260],{"class":256}," access.log\n",[236,262,264],{"class":238,"line":263},3,[236,265,267],{"emptyLinePlaceholder":266},true,"\n",[236,269,271],{"class":238,"line":270},4,[236,272,273],{"class":242},"# 2. 看所有非爬虫(排除 UA 里带 curl 和 python-requests 的行)\n",[236,275,277,279,282,285],{"class":238,"line":276},5,[236,278,51],{"class":249},[236,280,281],{"class":252}," -vE",[236,283,284],{"class":256}," '\" (curl|python-requests)\u002F'",[236,286,260],{"class":256},[236,288,290],{"class":238,"line":289},6,[236,291,267],{"emptyLinePlaceholder":266},[236,293,295],{"class":238,"line":294},7,[236,296,297],{"class":242},"# 3. 按 IP 精确搜(用 -F 防止 . 被当成任意字符正则)\n",[236,299,301,303,306,309],{"class":238,"line":300},8,[236,302,51],{"class":249},[236,304,305],{"class":252}," -F",[236,307,308],{"class":256}," '10.0.0.5'",[236,310,260],{"class":256},[236,312,314],{"class":238,"line":313},9,[236,315,267],{"emptyLinePlaceholder":266},[236,317,319],{"class":238,"line":318},10,[236,320,321],{"class":242},"# 4. 数 200 状态码有多少条\n",[236,323,325,327,330,333],{"class":238,"line":324},11,[236,326,51],{"class":249},[236,328,329],{"class":252}," -cE",[236,331,332],{"class":256}," '\" 200 '",[236,334,260],{"class":256},[236,336,338],{"class":238,"line":337},12,[236,339,340],{"class":242},"# 输出:2\n",[122,342,343],{"id":343},"最常见坑",[15,345,346,103,356,359,360,363,364,366,367,370,371,373],{},[49,347,348,349,351,352,355],{},"没加 ",[100,350,154],{}," 把 IP 的 ",[100,353,354],{},"."," 当正则匹配了",[100,357,358],{},"grep '10.0.0.5' log"," 会匹配 ",[100,361,362],{},"102030.5","(",[100,365,354],{}," 匹配任意字符)。\n匹配 ",[49,368,369],{},"IP \u002F 文件路径 \u002F URL \u002F 版本号(1.2.3)"," 这种自带元字符的字符串,一律加 ",[100,372,154],{},"。",[115,375],{},[11,377,379],{"id":378},"awk字段切片与统计","awk:字段切片与统计",[15,381,382,383,386,387,390,391,394,395,398,399,402],{},"awk 的核心模型:",[49,384,385],{},"一条输入 = 一条记录(record)",",一条记录按分隔符切成多个字段,",[100,388,389],{},"$1"," 第 1 个字段、",[100,392,393],{},"$2"," 第 2 个……",[100,396,397],{},"$NF"," 最后一个字段、",[100,400,401],{},"$0"," 整行。",[122,404,405],{"id":405},"最常用内建变量",[22,407,408,418],{},[25,409,410],{},[28,411,412,415],{},[31,413,414],{},"变量",[31,416,417],{},"含义",[41,419,420,430,440,450],{},[28,421,422,427],{},[46,423,424],{},[100,425,426],{},"FS",[46,428,429],{},"输入字段分隔符(默认「任意空白字符」空格\u002FTab 都算一个)",[28,431,432,437],{},[46,433,434],{},[100,435,436],{},"OFS",[46,438,439],{},"输出字段分隔符(默认空格)",[28,441,442,447],{},[46,443,444],{},[100,445,446],{},"NR",[46,448,449],{},"当前第几条记录(行号)",[28,451,452,457],{},[46,453,454],{},[100,455,456],{},"NF",[46,458,459,460,462],{},"当前记录的字段数(所以 ",[100,461,397],{}," 是最后 1 列)",[15,464,465,466,469],{},"语法:",[100,467,468],{},"awk '条件 {动作}' 文件",",条件没写=对每行都做。",[122,471,227],{"id":472},"真实示例-1",[105,474,476],{"className":230,"code":475,"language":232,"meta":113,"style":113},"# 1. 取出每条 log 的 IP + 状态码(第 1 列 + 第 9 列)\nawk '{print $1, $9}' access.log\n# 输出:\n# 192.168.1.10 200\n# 10.0.0.5 401\n# ...\n",[100,477,478,483,492,497,502,507],{"__ignoreMap":113},[236,479,480],{"class":238,"line":239},[236,481,482],{"class":242},"# 1. 取出每条 log 的 IP + 状态码(第 1 列 + 第 9 列)\n",[236,484,485,487,490],{"class":238,"line":246},[236,486,68],{"class":249},[236,488,489],{"class":256}," '{print $1, $9}'",[236,491,260],{"class":256},[236,493,494],{"class":238,"line":263},[236,495,496],{"class":242},"# 输出:\n",[236,498,499],{"class":238,"line":270},[236,500,501],{"class":242},"# 192.168.1.10 200\n",[236,503,504],{"class":238,"line":276},[236,505,506],{"class":242},"# 10.0.0.5 401\n",[236,508,509],{"class":238,"line":289},[236,510,511],{"class":242},"# ...\n",[105,513,515],{"className":230,"code":514,"language":232,"meta":113,"style":113},"# 2. 自定义分隔符:取请求路径(按双引号切,第 2 段是 \"GET \u002Fxxx HTTP\u002F1.1\",再按空格切第 2 个)\nawk -F'\"' '{print $2}' access.log | awk '{print $2}'\n# 输出:\n# \u002Fdocs\u002Fgit\u002Fgit-stash\n# \u002Fapi\u002Flogin\n# \u002Fdocs\u002Flinux\u002Fgrep-awk-sed\n# \u002Fwp-login.php\n# \u002Fapi\u002Flogin\n",[100,516,517,522,547,551,556,561,566,571],{"__ignoreMap":113},[236,518,519],{"class":238,"line":239},[236,520,521],{"class":242},"# 2. 自定义分隔符:取请求路径(按双引号切,第 2 段是 \"GET \u002Fxxx HTTP\u002F1.1\",再按空格切第 2 个)\n",[236,523,524,526,528,531,534,537,541,544],{"class":238,"line":246},[236,525,68],{"class":249},[236,527,305],{"class":252},[236,529,530],{"class":256},"'\"'",[236,532,533],{"class":256}," '{print $2}'",[236,535,536],{"class":256}," access.log",[236,538,540],{"class":539},"szBVR"," |",[236,542,543],{"class":249}," awk",[236,545,546],{"class":256}," '{print $2}'\n",[236,548,549],{"class":238,"line":263},[236,550,496],{"class":242},[236,552,553],{"class":238,"line":270},[236,554,555],{"class":242},"# \u002Fdocs\u002Fgit\u002Fgit-stash\n",[236,557,558],{"class":238,"line":276},[236,559,560],{"class":242},"# \u002Fapi\u002Flogin\n",[236,562,563],{"class":238,"line":289},[236,564,565],{"class":242},"# \u002Fdocs\u002Flinux\u002Fgrep-awk-sed\n",[236,567,568],{"class":238,"line":294},[236,569,570],{"class":242},"# \u002Fwp-login.php\n",[236,572,573],{"class":238,"line":300},[236,574,560],{"class":242},[105,576,578],{"className":230,"code":577,"language":232,"meta":113,"style":113},"# 3. 只保留状态码非 200 的行,输出 IP 和 状态码(用条件)\nawk '$9 != 200 {print $1, $9}' access.log\n# 输出:\n# 10.0.0.5 401\n# 45.88.12.3 404\n",[100,579,580,585,594,598,602],{"__ignoreMap":113},[236,581,582],{"class":238,"line":239},[236,583,584],{"class":242},"# 3. 只保留状态码非 200 的行,输出 IP 和 状态码(用条件)\n",[236,586,587,589,592],{"class":238,"line":246},[236,588,68],{"class":249},[236,590,591],{"class":256}," '$9 != 200 {print $1, $9}'",[236,593,260],{"class":256},[236,595,596],{"class":238,"line":263},[236,597,496],{"class":242},[236,599,600],{"class":238,"line":270},[236,601,506],{"class":242},[236,603,604],{"class":238,"line":276},[236,605,606],{"class":242},"# 45.88.12.3 404\n",[105,608,610],{"className":230,"code":609,"language":232,"meta":113,"style":113},"# 4. 统计每个状态码出现的次数(分组 sum,awk 最强项,不要再去写 Python)\nawk '{cnt[$9]++} END {for (code in cnt) print code, cnt[code]}' access.log\n# 输出示例:\n# 200 2\n# 401 1\n# 404 1\n",[100,611,612,617,626,631,636,641],{"__ignoreMap":113},[236,613,614],{"class":238,"line":239},[236,615,616],{"class":242},"# 4. 统计每个状态码出现的次数(分组 sum,awk 最强项,不要再去写 Python)\n",[236,618,619,621,624],{"class":238,"line":246},[236,620,68],{"class":249},[236,622,623],{"class":256}," '{cnt[$9]++} END {for (code in cnt) print code, cnt[code]}'",[236,625,260],{"class":256},[236,627,628],{"class":238,"line":263},[236,629,630],{"class":242},"# 输出示例:\n",[236,632,633],{"class":238,"line":270},[236,634,635],{"class":242},"# 200 2\n",[236,637,638],{"class":238,"line":276},[236,639,640],{"class":242},"# 401 1\n",[236,642,643],{"class":238,"line":289},[236,644,645],{"class":242},"# 404 1\n",[105,647,649],{"className":230,"code":648,"language":232,"meta":113,"style":113},"# 5. 字段分隔符改成冒号(比如拿 \u002Fetc\u002Fpasswd 的 shell)\nawk -F: '$7 == \"\u002Fbin\u002Fbash\" {print $1, $6}' \u002Fetc\u002Fpasswd\n",[100,650,651,656],{"__ignoreMap":113},[236,652,653],{"class":238,"line":239},[236,654,655],{"class":242},"# 5. 字段分隔符改成冒号(比如拿 \u002Fetc\u002Fpasswd 的 shell)\n",[236,657,658,660,663,666],{"class":238,"line":246},[236,659,68],{"class":249},[236,661,662],{"class":252}," -F:",[236,664,665],{"class":256}," '$7 == \"\u002Fbin\u002Fbash\" {print $1, $6}'",[236,667,668],{"class":256}," \u002Fetc\u002Fpasswd\n",[122,670,343],{"id":671},"最常见坑-1",[673,674,675,693],"ul",{},[676,677,678,679,682,683,686,687,689,690],"li",{},"用 ",[100,680,681],{},","," 分隔 ",[100,684,685],{},"print"," 的多个参数时输出之间会插空格(",[100,688,436],{},"),想连写就直接拼:",[100,691,692],{},"print $1 \":\" $9",[676,694,695,698],{},[100,696,697],{},"END {}"," 里的代码是所有行处理完才执行,写在外面的代码每行都会跑——很多人把统计逻辑没写进 END 导致每行都打印一次",[115,700],{},[11,702,704],{"id":703},"sed替换和编辑","sed:替换和编辑",[15,706,707,708,711,712,715,716,719],{},"sed = ",[49,709,710],{},"S","tream ",[49,713,714],{},"Ed","itor,对输入的每一行按脚本顺序执行指令,然后输出。绝大多数场景只用 ",[100,717,718],{},"s","(substitute 替换)指令。",[122,721,723,725],{"id":722},"s-指令语法",[100,724,718],{}," 指令语法",[105,727,730],{"className":728,"code":729,"language":110},[108],"s\u002F要匹配的正则\u002F替换内容\u002F修饰符\n",[100,731,729],{"__ignoreMap":113},[15,733,734],{},"修饰符:",[673,736,737,740,746,752],{},[676,738,739],{},"不加:只替换每行第一个匹配",[676,741,742,745],{},[100,743,744],{},"g",":global,每行全部替换(95% 场景带这个)",[676,747,748,751],{},[100,749,750],{},"i",":忽略大小写",[676,753,754,756,757,759],{},[100,755,15],{},":打印被替换的行(常和 ",[100,758,181],{}," 搭配)",[122,761,763,764],{"id":762},"分隔符可选不是只能用","分隔符可选:不是只能用 ",[100,765,766],{},"\u002F",[15,768,769,770,773,774,773,777,103],{},"只要三个字符一致即可。替换内容含 URL\u002F路径时推荐用 ",[100,771,772],{},"#"," ",[100,775,776],{},"@",[100,778,779],{},"|",[105,781,783],{"className":230,"code":782,"language":232,"meta":113,"style":113},"# 写法 1:全是 \u002F 要疯狂转义(不要这么写)\nsed 's\u002F\\\u002Fvar\\\u002Fwww\\\u002Fhtml\u002F\\\u002Fsrv\\\u002Fwww\u002Fg' nginx.conf\n\n# 写法 2:用 # 当分隔符(推荐)\nsed 's#\u002Fvar\u002Fwww\u002Fhtml#\u002Fsrv\u002Fwww#g' nginx.conf\n",[100,784,785,790,800,804,809],{"__ignoreMap":113},[236,786,787],{"class":238,"line":239},[236,788,789],{"class":242},"# 写法 1:全是 \u002F 要疯狂转义(不要这么写)\n",[236,791,792,794,797],{"class":238,"line":246},[236,793,85],{"class":249},[236,795,796],{"class":256}," 's\u002F\\\u002Fvar\\\u002Fwww\\\u002Fhtml\u002F\\\u002Fsrv\\\u002Fwww\u002Fg'",[236,798,799],{"class":256}," nginx.conf\n",[236,801,802],{"class":238,"line":263},[236,803,267],{"emptyLinePlaceholder":266},[236,805,806],{"class":238,"line":270},[236,807,808],{"class":242},"# 写法 2:用 # 当分隔符(推荐)\n",[236,810,811,813,816],{"class":238,"line":276},[236,812,85],{"class":249},[236,814,815],{"class":256}," 's#\u002Fvar\u002Fwww\u002Fhtml#\u002Fsrv\u002Fwww#g'",[236,817,799],{"class":256},[122,819,227],{"id":820},"真实示例-2",[105,822,824],{"className":230,"code":823,"language":232,"meta":113,"style":113},"# 1. 把 access.log 里所有 HTTP\u002F1.1 改成 HTTP\u002F2(只是 stdout 输出,不改原文件)\nsed 's#HTTP\u002F1.1#HTTP\u002F2#g' access.log\n\n# 2. 原地修改文件(-i,Linux 上 GNU sed 直接写;macOS BSD sed 需要 -i '')\nsed -i 's#127.0.0.1:8080#0.0.0.0:3000#g' .env\n\n# 3. 删除包含 wp-login.php 的行(常见扫垃圾请求行)\nsed '\u002Fwp-login\\.php\u002Fd' access.log\n\n# 4. 只打印第 3 到第 5 行\nsed -n '3,5p' access.log\n",[100,825,826,831,840,844,849,862,866,871,880,884,889],{"__ignoreMap":113},[236,827,828],{"class":238,"line":239},[236,829,830],{"class":242},"# 1. 把 access.log 里所有 HTTP\u002F1.1 改成 HTTP\u002F2(只是 stdout 输出,不改原文件)\n",[236,832,833,835,838],{"class":238,"line":246},[236,834,85],{"class":249},[236,836,837],{"class":256}," 's#HTTP\u002F1.1#HTTP\u002F2#g'",[236,839,260],{"class":256},[236,841,842],{"class":238,"line":263},[236,843,267],{"emptyLinePlaceholder":266},[236,845,846],{"class":238,"line":270},[236,847,848],{"class":242},"# 2. 原地修改文件(-i,Linux 上 GNU sed 直接写;macOS BSD sed 需要 -i '')\n",[236,850,851,853,856,859],{"class":238,"line":276},[236,852,85],{"class":249},[236,854,855],{"class":252}," -i",[236,857,858],{"class":256}," 's#127.0.0.1:8080#0.0.0.0:3000#g'",[236,860,861],{"class":256}," .env\n",[236,863,864],{"class":238,"line":289},[236,865,267],{"emptyLinePlaceholder":266},[236,867,868],{"class":238,"line":294},[236,869,870],{"class":242},"# 3. 删除包含 wp-login.php 的行(常见扫垃圾请求行)\n",[236,872,873,875,878],{"class":238,"line":300},[236,874,85],{"class":249},[236,876,877],{"class":256}," '\u002Fwp-login\\.php\u002Fd'",[236,879,260],{"class":256},[236,881,882],{"class":238,"line":313},[236,883,267],{"emptyLinePlaceholder":266},[236,885,886],{"class":238,"line":318},[236,887,888],{"class":242},"# 4. 只打印第 3 到第 5 行\n",[236,890,891,893,896,899],{"class":238,"line":324},[236,892,85],{"class":249},[236,894,895],{"class":252}," -n",[236,897,898],{"class":256}," '3,5p'",[236,900,260],{"class":256},[122,902,343],{"id":903},"最常见坑-2",[15,905,906,911,914,915,917,918,921,922,924],{},[49,907,908,910],{},[100,909,201],{}," 参数在 macOS 上和 Linux 上不一致",[912,913],"mac-os",{},"(BSD sed)要求 ",[100,916,201],{}," 后面必须跟备份后缀,想不备份写 ",[100,919,920],{},"-i ''",";GNU sed 直接 ",[100,923,201],{}," 就行。\n如果脚本要跨平台,统一写成:",[105,926,928],{"className":230,"code":927,"language":232,"meta":113,"style":113},"# GNU sed + BSD sed 都能跑的写法:先备份再删备份\nsed -i.bak 's\u002Ffoo\u002Fbar\u002Fg' file && rm file.bak\n",[100,929,930,935],{"__ignoreMap":113},[236,931,932],{"class":238,"line":239},[236,933,934],{"class":242},"# GNU sed + BSD sed 都能跑的写法:先备份再删备份\n",[236,936,937,939,942,945,948,952,955],{"class":238,"line":246},[236,938,85],{"class":249},[236,940,941],{"class":252}," -i.bak",[236,943,944],{"class":256}," 's\u002Ffoo\u002Fbar\u002Fg'",[236,946,947],{"class":256}," file",[236,949,951],{"class":950},"sVt8B"," && ",[236,953,954],{"class":249},"rm",[236,956,957],{"class":256}," file.bak\n",[115,959],{},[11,961,963],{"id":962},"组合管道示例3-条一起用","组合管道示例:3 条一起用",[15,965,966,967,970],{},"需求:统计 access.log 里,",[49,968,969],{},"排除爬虫 UA",",非 200 的请求中,按请求路径分组取 Top 3。",[105,972,974],{"className":230,"code":973,"language":232,"meta":113,"style":113},"grep -vE '\" (curl|python-requests)\u002F' access.log \\\n  | awk '$9 != 200' \\\n  | awk -F'\"' '{print $2}' \\\n  | awk '{print $2}' \\\n  | sort \\\n  | uniq -c \\\n  | sort -rn \\\n  | head -n 3\n",[100,975,976,989,1001,1015,1025,1034,1046,1057],{"__ignoreMap":113},[236,977,978,980,982,984,986],{"class":238,"line":239},[236,979,51],{"class":249},[236,981,281],{"class":252},[236,983,284],{"class":256},[236,985,536],{"class":256},[236,987,988],{"class":252}," \\\n",[236,990,991,994,996,999],{"class":238,"line":246},[236,992,993],{"class":539},"  |",[236,995,543],{"class":249},[236,997,998],{"class":256}," '$9 != 200'",[236,1000,988],{"class":252},[236,1002,1003,1005,1007,1009,1011,1013],{"class":238,"line":263},[236,1004,993],{"class":539},[236,1006,543],{"class":249},[236,1008,305],{"class":252},[236,1010,530],{"class":256},[236,1012,533],{"class":256},[236,1014,988],{"class":252},[236,1016,1017,1019,1021,1023],{"class":238,"line":270},[236,1018,993],{"class":539},[236,1020,543],{"class":249},[236,1022,533],{"class":256},[236,1024,988],{"class":252},[236,1026,1027,1029,1032],{"class":238,"line":276},[236,1028,993],{"class":539},[236,1030,1031],{"class":249}," sort",[236,1033,988],{"class":252},[236,1035,1036,1038,1041,1044],{"class":238,"line":289},[236,1037,993],{"class":539},[236,1039,1040],{"class":249}," uniq",[236,1042,1043],{"class":252}," -c",[236,1045,988],{"class":252},[236,1047,1048,1050,1052,1055],{"class":238,"line":294},[236,1049,993],{"class":539},[236,1051,1031],{"class":249},[236,1053,1054],{"class":252}," -rn",[236,1056,988],{"class":252},[236,1058,1059,1061,1064,1066],{"class":238,"line":300},[236,1060,993],{"class":539},[236,1062,1063],{"class":249}," head",[236,1065,895],{"class":252},[236,1067,1068],{"class":252}," 3\n",[15,1070,1071],{},"拆解:",[1073,1074,1075,1081,1087,1094,1100,1106],"ol",{},[676,1076,1077,1080],{},[100,1078,1079],{},"grep -vE",":先排除爬虫行",[676,1082,1083,1086],{},[100,1084,1085],{},"awk '$9 != 200'",":拿非 200 行",[676,1088,1089,1090,1093],{},"两个 ",[100,1091,1092],{},"awk -F'\"'"," + 空格切:抽出路径",[676,1095,1096,1099],{},[100,1097,1098],{},"sort | uniq -c",":分组计数(经典写法)",[676,1101,1102,1105],{},[100,1103,1104],{},"sort -rn",":按计数从大到小",[676,1107,1108,1111],{},[100,1109,1110],{},"head -n 3",":取前 3",[115,1113],{},[11,1115,1117],{"id":1116},"常见问题-faq","常见问题 FAQ",[122,1119,1121],{"id":1120},"q1-想在配置文件里注释掉某一行前面加-用-sed-怎么做","Q1. 想在配置文件里注释掉某一行(前面加 #),用 sed 怎么做?",[105,1123,1125],{"className":230,"code":1124,"language":232,"meta":113,"style":113},"# 把 listen 80; 这一行前面加 #\nsed '\u002Flisten 80;\u002Fs#^#\\##' nginx.conf\n\n# 反向:取消注释(去掉行首的 #)\nsed 's#^#\\?\\(listen 80;\\)#\\1#' nginx.conf\n",[100,1126,1127,1132,1141,1145,1150],{"__ignoreMap":113},[236,1128,1129],{"class":238,"line":239},[236,1130,1131],{"class":242},"# 把 listen 80; 这一行前面加 #\n",[236,1133,1134,1136,1139],{"class":238,"line":246},[236,1135,85],{"class":249},[236,1137,1138],{"class":256}," '\u002Flisten 80;\u002Fs#^#\\##'",[236,1140,799],{"class":256},[236,1142,1143],{"class":238,"line":263},[236,1144,267],{"emptyLinePlaceholder":266},[236,1146,1147],{"class":238,"line":270},[236,1148,1149],{"class":242},"# 反向:取消注释(去掉行首的 #)\n",[236,1151,1152,1154,1157],{"class":238,"line":276},[236,1153,85],{"class":249},[236,1155,1156],{"class":256}," 's#^#\\?\\(listen 80;\\)#\\1#'",[236,1158,799],{"class":256},[122,1160,1162],{"id":1161},"q2-awk-里怎么写-ifelse要不要写-bash","Q2. awk 里怎么写 if\u002Felse?要不要写 bash?",[15,1164,1165],{},"直接写就行。awk 是完整的迷你语言,别什么都去开 Python:",[105,1167,1169],{"className":230,"code":1168,"language":232,"meta":113,"style":113},"awk '{\n  if ($9 >= 500) print \"5xx:\", $0\n  else if ($9 >= 400) print \"4xx:\", $0\n  else print \"ok:\", $1\n}' access.log\n",[100,1170,1171,1178,1183,1188,1193],{"__ignoreMap":113},[236,1172,1173,1175],{"class":238,"line":239},[236,1174,68],{"class":249},[236,1176,1177],{"class":256}," '{\n",[236,1179,1180],{"class":238,"line":246},[236,1181,1182],{"class":256},"  if ($9 >= 500) print \"5xx:\", $0\n",[236,1184,1185],{"class":238,"line":263},[236,1186,1187],{"class":256},"  else if ($9 >= 400) print \"4xx:\", $0\n",[236,1189,1190],{"class":238,"line":270},[236,1191,1192],{"class":256},"  else print \"ok:\", $1\n",[236,1194,1195,1198],{"class":238,"line":276},[236,1196,1197],{"class":256},"}'",[236,1199,260],{"class":256},[122,1201,1203],{"id":1202},"q3-我想让-grep-结果高亮关键词但不改变管道输出","Q3. 我想让 grep 结果高亮关键词但不改变管道输出?",[15,1205,1206,1207,1210,1211,1214],{},"加 ",[100,1208,1209],{},"--color=always",",在交互式终端很好用;管道里建议 ",[100,1212,1213],{},"auto","(默认),否则 ANSI 颜色码会污染后面的 awk\u002Fsed 解析。",[115,1216],{},[11,1218,1219],{"id":1219},"更正记录",[673,1221,1222],{},[676,1223,1224],{},"2026-08-09:首版发布,校验环境 Debian 12 \u002F GNU 三件套版本如上。",[1226,1227,1228],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":113,"searchDepth":246,"depth":246,"links":1230},[1231,1232,1237,1242,1250,1251,1256],{"id":13,"depth":246,"text":13},{"id":119,"depth":246,"text":120,"children":1233},[1234,1235,1236],{"id":124,"depth":263,"text":124},{"id":227,"depth":263,"text":227},{"id":343,"depth":263,"text":343},{"id":378,"depth":246,"text":379,"children":1238},[1239,1240,1241],{"id":405,"depth":263,"text":405},{"id":472,"depth":263,"text":227},{"id":671,"depth":263,"text":343},{"id":703,"depth":246,"text":704,"children":1243},[1244,1246,1248,1249],{"id":722,"depth":263,"text":1245},"s 指令语法",{"id":762,"depth":263,"text":1247},"分隔符可选:不是只能用 \u002F",{"id":820,"depth":263,"text":227},{"id":903,"depth":263,"text":343},{"id":962,"depth":246,"text":963},{"id":1116,"depth":246,"text":1117,"children":1252},[1253,1254,1255],{"id":1120,"depth":263,"text":1121},{"id":1161,"depth":263,"text":1162},{"id":1202,"depth":263,"text":1203},{"id":1219,"depth":246,"text":1219},"linux","2026-08-09","运维每天都用的 grep \u002F awk \u002F sed 三条命令怎么分工?本文用真实日志和 CSV 文件演示:grep 做过滤、awk 做字段切片与统计、sed 做替换和编辑,附每条命令最常用参数和坑点。",false,"md",{},"\u002Fdocs\u002Flinux\u002Fgrep-awk-sed",{"title":5,"description":1259},"grep-awk-sed","docs\u002Flinux\u002Fgrep-awk-sed",[1268,1269,1270],"三条命令分工:grep=拿行(过滤),awk=拿字段并计算, sed=改内容(替换\u002F删除\u002F插入)。原则上能一条 grep 解决就别上 awk,能 awk 就别写 Python 脚本。","grep 最常用三件套:grep -E(扩展正则)、grep -v(取反)、grep -F(固定字符串不解析正则)。切记带元字符的字符串匹配用 -F,否则 . * + 会被当成正则。","awk 的核心是 $1\u002F$2...$NF 字段、FS\u002FOFS 分隔符、NR\u002FNF 内建变量。sed 最常用的是 s\u002Fa\u002Fb\u002Fg 全局替换和 -i 原地修改;替换分隔符可以换成 # | @,避免 URL 里 \u002F 要转义。",[1272,1273,1274,1275],"linux 命令","grep 正则","awk 教程","sed 替换","BYNSWdERIaUbDyai5V2Zm2NzrZ4RQcYjQe7HCooVocg",[],1794088893180]