news 2026/9/30 3:24:40

Linux文本处理命令实战:grep、awk、sed与管道组合指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux文本处理命令实战:grep、awk、sed与管道组合指南

我最早意识到文本处理命令这东西的价值,是在一次线上日志排查里。某个跳转接口突然报错,启动文件、环境变量、进程输出全都要靠命令去翻。就在那次,我把cat、grep、awk、sed一口气串下来,不到十分钟就定位了问题。从那时起,我确实认为 Linux 和 Unix 下的基础文本处理命令,是所有人都应该尽早掌握的基本功。无论你是开发、运维还是数据分析,每条命令单独看平淡无奇,组合起来却是非常趁手的武器。这篇文章就聊聊这些命令怎么用、怎么组合、在哪里有坑,尽量让刚接触命令行的朋友也能照着操作。

1. 聊透文本处理的思维框架

1.1 文本处理为什么是 Linux/Unix 的看家本领

Linux/Unix 系统的设计哲学里有一句话叫“一切皆文件”,配置文件是文本、日志是文本、标准输入输出是文本,甚至很多设备节点也以文本形式呈现。这意味着你在系统上做的绝大多数操作,本质上都是在和文本打交道。图形界面当然也有,但命令行处理文本有一个无法替代的好处:可复用、可脚本化。你今天在终端里敲的一串命令,明天可以写进.sh脚本,后天可以放到定时任务里自动执行。

我刚接触 Linux 时有个习惯:遇到问题就打开浏览器去搜“怎么查看某个日志”,搜到一条命令就复制粘贴。后来发现这样效率很低,因为你抄来的命令往往不理解它为什么这样写,换个场景就不会改。真正让我开窍的是把命令当成“动词”来理解:grep是做筛选的,awk是做字段提取的,sed是做替换的,sort和uniq是做排序和去重的。把动词串起来,复杂问题就能拆成一条条管道命令。

这里要纠正一个误区:很多人觉得文本处理是“老年运维”才需要的东西。其实不是。开发要查日志定位线上问题,数据分析师要预处理 CSV 数据,测试要比对接口返回结果,都离不开这些命令。我自己带过的新人里,凡是命令行用得熟的,解决线上问题的速度普遍快一大截。因为当你面对一台只有命令行环境的服务器时,文本处理命令就是唯一能依赖的工具。

1.2 文本处理的基本思路:四个动作

我把文本处理归纳成四个基本动作:查看、筛选、变换、统计。你做的所有复杂处理,本质上都是这四个动作的组合。

查看就是先把文本内容“看”清楚。文件有多少行、文件长什么样、最新的日志追加了什么内容,这是所有操作的第一步。筛选是“留想要的,去不想要的”,典型工具是grep,比如只关心含有ERROR的行。变换是把文本结构改造成另一种形态,比如把换行符去掉、把某列拆出来、把某个字符串批量替换。变换类命令最多,cut、tr、sed、awk、paste都算。统计是最后一步,算一下有多少行、多少个唯一值、哪个值出现的次数最多,典型工具是wc和uniq -c。

这四个动作通常不是孤立使用的。比如我要统计日志里某个接口失败了多少次,脑子里的逻辑链是:先用grep筛出包含该接口的行,再用grep筛出包含HTTP/1.1" 5的失败状态码,然后用wc -l数行数。整个过程不需要写程序,几个命令一条管道就搞定了。

理解了这个框架,你就不会被单个命令的复杂参数吓到。每次拿到一个新需求,先问自己:这里要做的是查看、筛选、变换还是统计?确定了动作,再去找对应的命令和参数,思路会清晰很多。

1.3 管道和标准输入输出:文本处理的连接件

前面提到的组合能力,最大的功臣是管道符号|。它做的事情很简单:把左边命令的“标准输出”接到右边命令的“标准输入”,让数据像流水一样流过一长串处理环节。

我用一个生活类比解释管道:假设你有一堆土豆,需要去皮、切块、煮熟。命令就像不同的加工机器,管道就是传送带。土豆(文本)从第一台机器(cat读取文件)进入,经过去皮机(grep筛掉不要的行),再经过切块机(awk提取字段),最后落到收集筐(wc统计数量)。你不需要把中间结果保存成文件再手动喂给下一台机器,传送带直接帮你衔接好了。

这里有个新手经常困惑的问题:为什么有的命令能用管道接收数据,有的不行?其实关键看命令是否读取“标准输入”。grep、awk、sed都可以从管道接收内容,但vim这种交互式编辑器就不行。另外要注意,部分命令虽然能接收标准输入,但处理完未必输出到标准输出,比如rm就不会输出处理结果。所以写管道前,最好先确认每个环节的输入输出是否符合预期。

2. 高频文本处理命令逐个拆解

2.1 查看与输出类:cat、head、tail、less、wc

cat是最基础的查看命令,它的名字来自 concatenate,本意是“连接文件”,但因为能直接输出文件内容,被当成了查看工具。实际使用中我很少直接用cat看大文件,因为会把终端刷爆。我更喜欢用cat -n查看带行号的短文件,比如cat -n /etc/hosts,既能看内容又能知道行号位置。

head和tail是查看文件两端的命令。head -n 20 file看前 20 行,tail -n 20 file看后 20 行。运维场景里最有价值的是tail -f file,它能持续跟踪文件的新增内容。我排查线上问题时,经常同时开好几个终端窗口,用tail -f盯着不同的日志文件。这里有个小技巧:tail -F(大写)能处理文件被轮转的情况,比如日志文件被 logrotate 改名重建后,tail -F会自动切换到新文件,而tail -f会跟丢。

less是分页查看工具,适合看大文件。它和more的区别是less支持上下翻页和搜索,输入/关键词就能高亮定位。我自己的习惯是:文件超过一屏就用less,不要cat,这是用几次终端刷屏换来的教训。

wc是统计工具,wc -l数行数,wc -w数字数,wc -c数字节数。排查问题时我几乎必用wc -l确认日志规模,先知道文件多大,再决定用什么策略处理。举个例子,一个 10 万行的日志文件和 100 行的日志文件,处理思路完全不同:100 行可以直接cat看全貌,10 万行就得先grep缩小范围。

2.2 筛选与查找类:grep 家族的常用参数

grep是文本处理里使用频率最高的命令,没有之一。它的核心功能是“按模式筛行”:给定一个模式,把所有匹配的行输出出来。最简单的用法是grep 关键字 文件名,比如grep ERROR app.log,把日志里所有包含 ERROR 的行列出来。

参数方面,我按使用频率排个序:-i忽略大小写,排查日志时经常用到,因为错误关键字可能是 Error、ERROR、error 混着出现。-v反向匹配,把不包含模式的行输出。这个在过滤噪音时很有用,比如grep -v DEBUG app.log排除调试信息。-E启用扩展正则,配合|实现多模式匹配,比如grep -E "ERROR|FATAL" app.log。-r递归搜索目录,比如grep -r "password" /etc/nginx/。-A、-B、-C分别表示输出匹配行的后 N 行、前 N 行、前后各 N 行。日志排查时-C 3非常实用,因为单独一条报错往往看不出问题,需要看上下文联动分析。

这里要提醒一个grep -v的经典误区:很多人想“排除包含 A 又包含 B 的行”,直接用grep -v A file | grep -v B file,这个写法其实有问题,因为第二个grep已经丢了 pipe 前面第一个grep的结果(如果管道用的|而不是file,写成grep -v A file | grep -v B才是对的)。更准确的逻辑是先用grep A筛出目标,再用grep -v B排除干扰项,顺序不能反过来。

grep和管道配合是最常见的姿势:cat app.log | grep ERROR。但既然grep本来就接收文件名参数,写成grep ERROR app.log更简洁,还能少一层进程开销。不过管道写法有时候也有价值:当你前面还有别的处理时,用管道能保持串联的连贯性。哪个顺手用哪个。

2.3 行列操作与排序统计类:cut、paste、tr、sort、uniq

这几个命令放在一起,是因为它们都作用于行列层面的“变形”。

cut是列提取命令。cut -d指定分隔符,-f指定取第几列。比如处理 CSV 文件,cut -d',' -f1,3 data.csv取第 1 列和第 3 列。-c按字符切割,cut -c1-10取前 10 个字符,适合处理固定宽度的文本。用cut时的坑是分隔符:如果一行里分隔符数量不一致,cut会按实际存在的最小字段数切,容易切出空字段。遇到这种情况,我会改用awk的-F参数,后面会讲到。

paste是列拼接命令,把多个文件按行拼在一起,用分隔符隔开。paste -d',' file1 file2可以把两个文件的内容按行合并成两列。实际场景里,paste用得没有cut多,但它和cut是天然的一对:一个负责拆、一个负责拼。

tr是字符转换命令,它处理的粒度是“字符”而不是“行”。最常用的两个场景:一是大小写转换,tr 'a-z' 'A-Z'把小写转大写;二是删除和替换字符,tr -d '\r'删除回车符(这个在 Windows 文件转到 Linux 时特别有用)。tr的经典用法还有把空格替换成制表符之类。注意tr不支持直接作用于文件,必须通过管道喂数据:cat file | tr 'a-z' 'A-Z'。

sort是排序命令,uniq是去重命令,这两个经常配合使用。这里有个关键原理:uniq只能去掉“相邻且相同”的行。如果数据没有经过排序,相同的行分散在不同位置,uniq就去不掉。所以标准姿势是先sort再uniq。sort -n按数字排序,sort -r降序,sort -k指定排序字段,sort -t指定字段分隔符。uniq -c会在每行前面加上一个计数值,这个功能在做统计时很常用。我举个例子:

sort access.log | uniq -c | sort -nr

这条管道把日志内容排序,统计每个唯一内容出现的次数,再按次数从高到低排序。很多“出现了什么、出现了几次”的问题都能用这条管道解决。

2.4 文本编辑类:sed 和 awk 的日常用法

sed是非交互式流编辑器,适合做“批量替换、删除、插入”。我最常用的两个功能是替换和行操作。

替换语法:sed 's/旧字符串/新字符串/g' file。注意s是替换命令,末尾的g表示“一行里所有匹配都替换”,不加g只替换每行第一个匹配。这里的分隔符不一定是/,遇到字符串里含有斜杠时可以把分隔符换成#或@,比如sed 's@/usr/local@/opt@g' file,能少写很多转义。

行操作语法:sed '3d' file删除第 3 行,sed '5,10d' file删除第 5 到 10 行,sed '3,5p' file打印第 3 到 5 行(需要配合-n使用,否则会重复打印)。这个我实际用得不多,更常用的还是替换。

要特别提醒:sed默认不会修改原文件,只是把处理结果输出到终端。真要修改文件要加-i参数。但-i是个双刃剑,我用sed的十年里,至少两次因为-i误改文件而后悔。我的习惯是sed -i.bak 's/xxx/yyy/g' file,这样会生成一个file.bak备份文件。改坏了能回滚,改对了再删备份也不迟。

awk是比sed更强大的文本处理工具,它本质上是“按行读入,按分隔符切字段,按条件操作”。最简单的入门用法是提取列:awk -F',' '{print $1, $3}' file,-F指定分隔符,$1表示第 1 列,$0表示整行,NF是当前行的字段数。

awk还能做条件过滤:awk -F',' '$3 > 100 {print $1}' file,当第 3 列大于 100 时打印第 1 列。加BEGIN和END可以处理“开头/末尾”逻辑:awk '{sum += $2} END {print sum}' file能直接求第 2 列的总和。这些只是awk的冰山一角,但对刚入门的人来说,掌握“切字段 + 条件 + 统计”已经能解决大部分问题了。

说到awk和cut的选择:cut处理简单固定分隔符很快,但如果字段前后有多余空格、分隔符不统一、或者需要做条件判断,cut就吃力了,直接用awk更稳。awk默认把连续空白(空格和制表符)视为一个分隔符,这对日志里用空格分隔的字段非常友好,比如访问日志提取 IP 地址,用awk '{print $1}' access.log就够了。

3. 实操案例:从日志中提取访问量 TOP 10 的来源 IP

3.1 场景与设计思路

讲完命令,我们来做一个完整的案例。假设你管理一台 Web 服务器,收到告警说某个接口响应变慢。你想先确认是不是某个来源 IP 在疯狂请求,于是打开 Nginx 访问日志access.log,希望提取访问量最大的前 10 个来源 IP。

先说设计思路。Nginx 访问日志的默认格式大致是:

192.168.1.10 - - [10/Oct/2024:13:55:36 +0800] "GET /api/data?page=1 HTTP/1.1" 200 1024 "-" "Mozilla/5.0"

可以看到第一列就是来源 IP。我的处理流程是:先确认日志规模,再提取 IP 列,然后做去重计数,最后排序取前 10。

这个流程里隐含了两个关键知识点:第一,awk的默认分隔符是连续空白,能正确提取空格分隔的第一字段;第二,uniq -c只能处理相邻相同行,必须先sort让相同 IP 相邻,再用uniq -c去重计数,之后还要再sort -nr按次数降序排序。如果你把sort | uniq -c的顺序写反,统计结果就会乱,这是新手最常踩的坑。

3.2 分步操作与逐步拆解

第一步:确认日志规模与格式。

wc -l /var/log/nginx/access.log head -n 3 /var/log/nginx/access.log

wc -l告诉我日志行数,head -n 3让我看清字段结构。假设输出 10 万行,这个规模完全可以用管道命令处理,不用写复杂程序。

第二步:提取 IP 字段。

awk '{print $1}' /var/log/nginx/access.log

这里我用awk而不是cut,原因很简单:Nginx 默认日志字段以空格分隔,但字段之间可能包含连续空格,cut -d' ' -f1遇到连续空格会把空串当字段,导致误切。awk默认按“连续空白切分”,正好规避这个坑。

第三步:排序让相同 IP 相邻。

awk '{print $1}' /var/log/nginx/access.log | sort

排序前awk的输出可能是有序或无序的,反正此时不需要关心。sort默认按字典序排,同 IP 会聚在一起。这里我给一个小建议:如果 IP 版本混用 IPv4 和 IPv6,可以用sort -V做版本排序,这里暂不展开。

第四步:去重计数。

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c

uniq -c输出的每行前面有一个数字,表示该行内容连续出现的次数。此时输出顺序是按 IP 字典序,但计数并未按大小排。

第五步:按计数降序排序并取前 10。

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10

sort -n让数字按数值比较,-r降序。降序排列后计数最大的 10 行在最前面,head -n 10取出它们。这就是最终的 TOP 10 列表。

完整命令一行搞定:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10

执行后输出类似:

5321 203.0.113.55 2890 198.51.100.23 1433 192.0.2.78

我通常加上一个判断:如果某个 IP 的访问量占比异常高,再往下查这个 IP 的具体请求内容。

3.3 管道组合的扩展:再多看几层

上面的管道只提取了 IP,实际排障往往还需要继续展开。我常用的扩展动作有:

按状态码统计,比如看看 5xx 错误集中在哪些接口:

awk '{print $9, $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 20

这里$9是状态码,$7是请求路径,输出哪些路径的哪些状态码出现最多。注意 Nginx 默认日志中$9是状态码列,如果日志格式改了要重新数位置。

筛选某个 IP 的请求,确认它到底在访问什么:

awk '$1 == "203.0.113.55" {print $4, $7, $9}' /var/log/nginx/access.log

这条命令把来源 IP 为203.0.113.55的行里,时间、请求路径、状态码打出来,定位这个 IP 的行为模式。

筛选 5xx 错误,并统计涉及路径:

grep 'HTTP/1.1" 5' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -n 10

这里的思路是先筛后取,先grep把含 5xx 状态的行留下来,再用awk提取请求路径。能感受到管道组合的魅力:每个命令只负责一件事,但层层配合后能回答非常具体的问题。

参数调整的时候,最简单的改动是head -n 10换成head -n 20或tail -n 10。用tail的场景更少见,比如想找“失败次数最少的 10 个路径”,就把最后的sort -nr去掉-r。

4. 常见问题与排查技巧实录

4.1 Windows 与 Unix 换行符差异

从 Windows 传到 Linux 的文本文件,经常出现每行末尾多一个^M字符,用cat -v file能看到。原因很简单:Windows 用\r\n表示换行,Unix/Linux 用\n,\r在 Linux 下就是个普通字符。

最直接的解决方法是tr -d '\r' < file > newfile,把回车符全部删掉。也可以用sed -i 's/\r$//' file,只删行尾的回车符。还有专门工具dos2unix file,一条命令搞定,装一下也很方便。

我实际遇到过类似问题的进阶版:用 Beyond Compare 这类工具比较 Windows 版本和 Unix 版本的文件时,明明内容一样却提示“大量差异”,本质就是换行符不一致。解决思路和上面一致,先把两边文件统一成 Unix 换行符再比较。处理完再看,差异基本就消失了。如果你的比较工具支持忽略换行符差异,勾上对应选项也行,但底层原理还是要懂的。

4.2 Unix socket 权限问题:Docker 连接报错的坑

很多人第一次在 Linux 上安装 Docker、运行完docker ps会碰到这样一条报错:

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock

这其实不是 Docker 命令本身的问题,而是 Unix socket 的权限问题。Docker 客户端要和服务端通信,靠的是/var/run/docker.sock这个 Unix 域套接字文件,当前用户却没有访问权限。

解决办法有几种: 第一种,把当前用户加入docker组,然后重新登录。

sudo usermod -aG docker $USER

第二种,临时用sudo docker,但不建议长期使用,因为那样所有 Docker 命令都以 root 权限运行,不符合权限最小化原则。

这个问题的本质是“Unix 系统里的文件权限模型”,和chmod、chown直接相关。理解了文本处理命令里的权限查看(比如ls -l输出的-rw-r--r--),再看 socket 文件权限,就很容易理解了。

4.3 管道使用中的经典误区

我在带人时,发现几个反复出现的管道误区,总结一下:

第一个是“把文件参数和管道混用”。比如cat file | grep xxx可以简化成grep xxx file,前者多了一步cat,起不到什么额外作用。当然,如果是“先看文件大小再 grep”之类的场景,先wc -l再grep是有意义的,但单纯的cat | grep属于多余动作。

第二个是“grep -v和head顺序搞错”。想“排除前几行不能看”,写成grep -v '^#' file | head是看懂前几行,但如果 head 放在 grep 前面,head -n 10 file | grep -v '^#'的含义就变了:先取前十行,再在前十行里排除注释。两种写法结果完全不同,写之前想清楚顺序。

第三个是“uniq不配合sort”。前面已经反复强调,uniq只能去除相邻重复行。你如果直接cat file | uniq -c,很可能统计结果严重偏小,因为重复项没有聚到一起。凡是统计唯一值或出现次数,先sort再uniq,这个顺序几乎不会错。

第四个是“管道后面接交互式命令”。比如cat file | less可以正常工作,但cat file | vim不行,因为vim不是从标准输入读内容的工具。遇到这种情况,要用进程替换vim <(cat file),或者直接vim file。反正裁剪命令时想清楚目标命令是否支持读标准输入。

4.4 高频命令速查与我的避坑心得

我把上面这些命令整理成一张速查表,工作里挂在手边很方便:

命令作用常用参数示例
cat连接文件并输出-n显示行号cat -n /etc/hosts
head查看文件开头-n N显示前 N 行head -n 20 app.log
tail查看文件结尾-f跟踪追加,-F处理轮转tail -f app.log
less分页查看/搜索,q退出less big.log
grep按模式筛行-i-v-E-A/-B/-C-rgrep -i error app.log
wc统计行/字/字节-l行数,-w字数,-c字节wc -l app.log
cut按分隔符切列-d分隔符,-f第几列cut -d, -f2 data.csv
paste按行合并文件-d指定分隔符paste -d, a.txt b.txt
tr字符替换/删除-d删除字符,字符集合转换tr -d '\r' < file
sort排序-n数字序,-r降序,-k指定列sort -nr
uniq去重统计-c统计出现次数sort file | uniq -c
sed流式编辑替换s///g替换,-i修改文件,-i.bak备份sed -i.bak 's/a/b/g' file
awk按字段处理文本-F指定分隔符,$n取列,{print}输出awk '{print $1}' file

最后分享几条我在实践中积累的避坑心得:

第一,sed -i一定加备份后缀。哪怕你觉得自己对替换内容十拿九稳,也建议sed -i.bak,给自己留条退路。我见过有人手滑把配置文件里的路径替换错了,没有备份只能去其他机器上找原文件,非常狼狈。

第二,处理大日志文件时,先wc -l确认规模,再决定策略。100 行文件用cat没问题,100 万行文件就要用grep和awk做前端筛选。有些人一开始就cat整个日志然后直接看,把终端刷爆不说,眼睛也看花了。

第三,组合命令之前,先单独跑一遍前半段,确认输出符合预期再串联。比如要统计 IP,先跑awk '{print $1}' file | head,确认提取的确实是 IP 列,再加sort和uniq -c。一步步验证,比一把梭哈容易排查问题。

第四,注意转义字符。grep、sed、awk里的特殊字符都需要转义处理。一个常见的例子是匹配点号.,在正则里它匹配任意字符,要匹配字面量就得写\.。写复杂匹配之前,先在小的测试文件上验证正则,再对真实数据跑。

这套命令看着多,但练起来很快。最有效的练习方式不是背参数,而是给自己设定真实任务:比如统计某个日志里的关键词出现次数、提取某个配置文件的指定字段、批量替换某个目录下的字符串。用任务驱动学习,几周后你会发现自己已经离不开管道命令了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 3:24:28

Flutter鸿蒙适配实战:社区App登录模块开发与踩坑记录

1. "享家社区"为什么把登录模块交给Flutter&#xff1a;选型与边界1.1 社区类App登录场景的特殊性"享家社区"是一个面向小区住户的社区服务App&#xff0c;登录模块是它最基础也最容易出问题的部分。住户通过它交物业费、报修、开门禁、收通知&#xff0c;…

作者头像 李华
网站建设 2026/9/30 3:21:19

分布式存储实战:选型、分层、副本与容量管理

大数据领域谈到底&#xff0c;总绕不开"到底存哪"这一步。很多团队一开始做数据平台&#xff0c;第一件事就是上一套分布式存储&#xff0c;可上了之后发现&#xff1a;容量是大了&#xff0c;但查询变慢&#xff1b;文件是能存了&#xff0c;但小文件多到元数据扛不…

作者头像 李华
网站建设 2026/9/30 3:21:19

VRRP网关冗余原理详解与eNSP双核心交换机实验实战

去年给一家小型企业做核心网络改造时&#xff0c;我碰到了一个特别典型的故障&#xff1a;接入层做了双链路&#xff0c;出口路由器也做了双机热备&#xff0c;结果核心交换机重启一次&#xff0c;整个办公室直接断网四十多分钟。事后排查原因很简单&#xff0c;全公司两百多台…

作者头像 李华
网站建设 2026/9/30 3:21:14

Flutter for OpenHarmony 实战:收入分析统计 App 开发全流程与避坑指南

去年年中&#xff0c;我接了手一个不算大但足够折腾的项目&#xff1a;在 OpenHarmony 设备上做一个生活助手 App&#xff0c;最核心的模块是收入分析统计——记录每笔收入&#xff0c;按日、周、月、年汇总&#xff0c;算分类占比&#xff0c;再看趋势。当时团队里没有人正经碰…

作者头像 李华
网站建设 2026/9/30 3:21:00

Git入门到精通:从版本控制基础到团队协作实战

你有没有经历过这样的时刻&#xff1a;项目文件夹里躺着一堆“项目方案最终版2.0&#xff08;千万别动&#xff09;”“项目方案_改稿_备份_final”这种名字的文件&#xff1f;我有。那是刚工作的第一年&#xff0c;三个人改同一个文档&#xff0c;没有版本管理&#xff0c;每天…

作者头像 李华