news 2026/9/9 19:56:16

Linux三剑客面试100题:grep、sed、awk高频考点深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux三剑客面试100题:grep、sed、awk高频考点深度解析

带过不少新人,也当过很多次面试官,Linux 命令行这一关几乎是必考的。而在命令行里,grep、sed、awk 这三兄弟又是绝对的主角。市面上讲三剑客的教程一抓一大把,但真正能对着面试题把原理、用法、坑点讲透的很少。这套 100 道题,是我结合 DeepSeek 做了一轮题目梳理,再按照实际工作场景重新组织和校验过的结果,覆盖了从基础匹配到日志统计分析再到复杂文本处理的完整链路。

这篇文章不打算搞“题目列表+简单答案”那种敷衍形式,而是把 100 道题拆解成五个大模块,每个模块挑出最有代表性的题目做深度解析,顺带把面试官真正想考察的点也给你点透。不管你是准备面试的求职者,还是带新人的老手,或者单纯想把三剑客用得再溜一点的运维和开发,这篇内容应该都能让你有收获。

1. 先看题库整体:100道题是怎么设计出来的

1.1 难度梯度与题目分布

拿到这 100 道题的第一件事,不是闷头刷,而是先看题目结构。我把整个题库按难度和主题做了个交叉分类,大致分布如下表:

主题方向初级题(了解命令)中级题(理解原理)高级题(综合实战)合计
正则表达式基础108220
grep 文件匹配与过滤108321
sed 流式编辑与替换810422
awk 列处理与统计615829
三剑客组合与shell集成2248
合计364321100

注意看 awk 的题量,占了将近三分之一,而且高级题里有一半落在 awk 上。这不是偶然。实际工作中,grep 负责“找”,sed 负责“改”,awk 负责“算”,但真正的统计、汇总、格式化输出这些硬骨头,几乎都是 awk 在扛。面试官心里也清楚,能把 awk 用得熟练的人,对文本处理的理解基本不会差。

再说难度梯度。36 道初级题主要考察“用没用过”,比如grep -c是数行数还是数字符数,sed 's/old/new/g'的 g 是什么作用,awk -F怎么指定分隔符。43 道中级题考察“懂不懂原理”,比如 grep 的 BRE 和 ERE 区别、sed 的模式空间和保持空间、awk 的 NR 和 FNR 差异。剩下的 21 道高级题基本是综合场景,比如“统计 Nginx 日志里每个 IP 的访问次数 Top10”“把第二列和第三列互换并去掉重复行”之类。

1.2 刷题的正确姿势

很多人刷题是看一题记一题答案,今天记住了,明天换一个问法又懵了。我的建议是:先建一个正则表达式的知识框架,再分工具逐个击破。

正则表达式是三剑客的公共地基。你可以在 Python、Perl 里写正则,但 Linux 三剑客用的正则又有自己的变体:基础正则(BRE)、扩展正则(ERE)、以及 PCRE(Perl 兼容正则)。grep 默认走 BRE,-E走 ERE,-P走 PCRE;sed 默认也是 BRE,-E可以切到 ERE;awk 则直接使用 ERE。不理解这层关系,很容易出现“同样的正则,在 grep 里能匹配,到 awk 里就报错”的困惑。

刷题的时候还有一个小技巧:不要只看标准答案,把答案的命令拆开,每部分是什么含义,去掉某个参数会怎样,换成另一个工具能不能实现同样的效果。三剑客很多功能是重叠的,比如“找包含某个关键字的行”,grep、sed、awk 都能做到,但各自适合的场景不同。把一道题用三种工具各写一遍,你对它们的边界感会清晰很多。

另外,这套题的整理我给 DeepSeek 提了几个细化的要求,比如“附上命令执行前后的对比”“易错点单独标注”“不要直接给答案,先给思路”,这些细节对于建立一个面试导向的复习体系很有帮助。AI 工具可以帮你批量生成题目和参考答案,但最后一定要自己做一遍,因为面试问答和实际敲命令是两码事。

2. grep 高频题组:匹配之外还有多少门道

2.1 从最简单的匹配说起:递归、排除与上下文

很多人的 grep 水平停留在grep keyword file,这远远不够。先看题库里的一道初级题:

题 7:在 /var/log 目录下所有 .log 文件中递归查找包含ERROR的行,并显示行号。

grep -rn "ERROR" /var/log --include="*.log"

-r是递归,-n是显示行号,--include限定文件类型。这三个参数是实际工作中最高频的组合,没有之一。但注意,-r-R是有区别的:-r在遇到符号链接时不会跟随,-R会。如果你处理的日志目录里存在 symlink,用-R才能查得全,但也可能因为链接循环导致意外输出。

再看一个容易答错的变体:

题 12:查找包含success但不包含failed的行。

这个需求听起来简单,但实际处理很讲究。最简单的方式是管道:

grep "success" file | grep -v "failed"

但如果你更熟悉 awk,一条命令也能搞定:

awk '/success/ && !/failed/' file

两道命令效果差不多,但面试官考察点不一样。第一种考察的是-v反向匹配和管道组合思路,第二种考察的是 awk 的多条件匹配能力。都写出来,能体现你的灵活度。

-v是 grep 的排除利器,但真正的坑在于:grep -v failed是排除包含failed子串的行,而不是排除单词failed本身。如果你的日志里出现not_failed或者failed_xxx,也会被排除。这种边界问题,恰恰是面试题里最爱埋的雷。

2.2 正则进阶:BRE、ERE 与 PCRE 到底差在哪

题库里有一道题特别能检验基本功:

题 23:匹配手机号格式(1 开头,第二位 3-9,总共 11 位数字),分别用 grep 默认语法和 grep -E 写出。

默认 grep 走 BRE,花括号表示次数必须转义:

grep -n '^1[3-9][0-9]\{9\}$' phones.txt

grep -E走 ERE,花括号不需要转义:

grep -nE '^1[3-9][0-9]{9}$' phones.txt

这道题的考点有两个。一是你是否清楚 BRE 和 ERE 在元字符转义上的差异:BRE 里?+{}()这些字符默认是字面含义,要表示特殊含义必须加反斜杠;ERE 恰好相反,这些字符默认就是特殊含义,加反斜杠反而表示字面字符。二是你是否知道^$表示行首行尾,这是做整行匹配的前提。

再进阶一点,PCRE 支持\d\w这种更简洁的写法,所以有些面试者会直接写:

grep -P '^1[3-9]\d{9}$' phones.txt

-P参数确实好用,但它依赖 PCRE 库,而且在高版本的 grep 里依然不是默认选项。在部分精简版系统或嵌入式环境里,-P可能不可用。面试时如果写-P,最好顺带说一句“这是 PCRE 扩展语法,某些环境需要额外支持”,显得你心里有数。

2.3 实战案例:日志与配置处理中的 grep

题库里的高级 grep 题基本都挂在场景上,比如:

题 41:从 access.log 中提取所有返回状态码为 500 的行,并统计数量。

这个需求 grep 只能做一半,提取行可以,统计数量要交给wc

grep " 500 " access.log | wc -l

这里有个细节:为什么要写成" 500 "而不是"500"?因为日志里可能有50001500这种字段,加前后空格是为了锚定独立的状态码字段。更严谨的做法是把响应码放到行尾匹配,比如grep ' 500$',具体要看你的日志格式。面试时能主动讲出这个细节,比死记命令要加分得多。

再举一个常见组合:提取 IP 并排序去重。

grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort | uniq -c | sort -rn

-o只输出匹配到的部分,而不是整行;sort | uniq -c统计每个 IP 出现次数;最后的sort -rn按次数从大到小排。这条命令是面试经典题,背下来不难,但能解释清楚-o的作用才算真懂。

关于 grep,我还有一个建议:日常工作中不要只依赖 grep 的默认行为。--color=auto让匹配结果高亮,排查问题的时候非常直观;-A-B-C可以输出匹配行的后文、前文和上下文,配合日志中的堆栈信息特别好用。这些参数看似零碎,但面试题里经常以“怎么写更高效”的形式出现。

3. sed 高频题组:流编辑器的三板斧

3.1 替换操作:定界符、转义与分组引用

sed 最核心的能力就是替换。先看一道初级题:

题 18:把文件里所有的foo替换为bar,并直接修改原文件。

sed -i 's/foo/bar/g' file.txt

三个关键点。一是-i,直接修改文件;但-i的写法在不同 sed 版本里有差异,Linux 的 GNU sed 直接加-i,macOS 的 BSD sed 需要-i ''。二是s是替换命令,g是全局替换,不加g的话,每行只替换第一个匹配。三是foo里的/如果换成路径,比如替换/usr/local/opt,定界符就要改,写成sed -i 's#/usr/local#/opt#g' file,这样可以免去大量转义。

面试官很喜欢在分组引用上出题:

题 26:把2024/01/05格式的日期转换成2024-01-05

sed -E 's#([0-9]{4})/([0-9]{2})/([0-9]{2})#\1-\2-\3#g' file

这个解法的核心是()分组和\1引用。注意-E参数,它让 sed 进入 ERE 模式,这样{}()都不需要转义。如果你不用-E,就得写成\([0-9]\{4\}\),可读性差很多,也容易写错。

这里有个易错点必须提醒:捕获组是从(出现的顺序编号的,\1是第一个左括号对应的内容。如果正则前面还有其他分组,编号会顺延,写错\1\2的顺序是新手最常见的问题。我建议在本地调试的时候,先不加-i,让 sed 输出到屏幕,确认无误后再加-i写回文件。

3.2 地址匹配与范围控制

sed 的地址匹配是另一个高频考点:

题 33:只删除文件第 10 行到第 20 行的内容。

sed '10,20d' file

d是删除命令。这个题简单,但很多人不理解10,20d中的逗号其实是一种“范围地址”的写法,它的规则是:从匹配到第一个地址开始,到匹配到第二个地址为止。范围不限于数字,也可以混合正则:

sed '/BEGIN/,/END/d' file

这条命令会删除从匹配BEGIN的行开始,到匹配END的行结束的所有内容。这种“区间删除”在清理配置文件片段、移除日志中的异常段时非常有用。

还有一道容易答错的题:

题 35:打印文件第 1 行到第 5 行,但不修改文件。

很多人的第一反应是sed -n '1,5p' file-n关闭默认输出,p命令显式打印。如果忘了-n,结果会非常难看:sed 默认会打印所有行,而匹配到的行会被打印两次。所以sed-np基本是绑定出现的,考试时只要看到p,先检查有没有-n

3.3 处理配置文件与日志流的经典场景

题 52:把 Nginx 配置里listen 80;全部改成listen 8080;,同时备份原文件。

sed -i.bak 's/listen 80;/listen 8080;/g' nginx.conf

-i.bak的意思是先备份为nginx.conf.bak,再执行替换。生产环境改配置一定要养成备份的习惯,这个参数就是为此设计的。如果你想更稳妥,可以先执行sed 's/listen 80;/listen 8080;/g' nginx.conf查看输出,确认无误后再加-i操作。

sed 还可以直接处理管道流,这是它“流编辑器”称号的来源:

tail -f app.log | sed 's/ERROR/【错误】/'

这个用法在处理实时日志时很实用,不改原文件,只修改输出,让日志里的关键字更醒目。面试时如果能主动说“sed 最大的特点是流式处理,所以它很适合在管道中充当文本修改器”,会比单纯背命令更有深度。

sed 的难点其实不在命令本身,而在于“模式空间”这个概念。很多人不理解sed每一行是独立处理的,跨行操作要用NH这些多行命令。面试题里如果出现“把两行合并成一行”“跨行替换”这类需求,基本都是考察模式空间和保持空间的配合。题库里这类题目偏难,我建议先把单行处理练熟,再研究NH,因为大多数实际需求用单行操作就能解决。

4. awk 高频题组:文本处理的“重武器”

4.1 字段分割与内置变量

awk 的处理模型是“按行读入,按列切分”。这个模型是理解 awk 一切特性的基础,也是它和 grep、sed 最本质的区别。

题 22:打印 /etc/passwd 中每个用户的用户名和登录 shell,分隔符是冒号。

awk -F: '{print $1, $7}' /etc/passwd

-F:指定冒号作为字段分隔符,$1是第一个字段,$7是第七个字段。看起来简单,但背后的机制值得展开:awk 默认分隔符是空白(空格或 Tab),-F可以临时指定。如果你在脚本里需要频繁切换分隔符,也可以在 BEGIN 块里设置:

awk 'BEGIN{FS=":"} {print $1, $7}' /etc/passwd

这两种写法等价,但BEGIN{FS=":"}更灵活,因为它只是赋值给内置变量FS,你甚至可以在处理过程中改变 FS 的值,让不同的行用不同的分隔符解析。

再嵌套一题:

题 29:统计当前目录下所有 .log 文件的总行数。

一个常见解法是:

cat *.log | wc -l

但 awk 也能做,而且能统计得更细:

awk '{count++} END{print count}' *.log

count++每读一行执行一次,END块在文件全部处理完后执行。count是没有预先声明的变量,awk 默认把它当数字用,初始值是 0。这种“未声明直接使用”的特性,使用起来很方便,但也容易踩坑——如果你拼错变量名,awk 不会报错,只会默默给你一个错误结果。

4.2 条件、循环与数组统计

awk 的真正威力在于它是一门“微型语言”。题库里这道题是绝对的高频:

题 48:统计 access.log 中每个 IP 的出现次数,并按次数降序输出前 10 个。

awk '{count[$1]++} END{for (ip in count) print count[ip], ip}' access.log | sort -rn | head -10

很多人会背这条命令,但面试官更想听你解释三个阶段:读入阶段逐行执行{count[$1]++},用 IP 作为数组下标累加计数;文件读完进入 END 阶段,用for (ip in count)遍历数组;输出结果后交给sort -rn排序,head -10取前 10。count[$1]++这种写法是 awk 做频次统计的核心模式,可以套用到几乎所有分组统计场景,比如按状态码统计、按用户统计、按时间分钟统计等。

再进阶一点:

题 55:求第二列数值的平均值,保留两位小数。

awk '{sum+=$2; n++} END{printf "%.2f\n", sum/n}' data.txt

printf是 awk 里格式化输出的函数,%.2f表示保留两位小数。如果数据文件是空的,n 等于 0,直接sum/n会得到一个无穷大或报错,健壮性好的写法应该加上n>0的判断,这是大数据量脚本里容易忽视的问题。

awk 的数组有一点和普通语言不同:它的下标可以是字符串,本质上是一个关联数组。这个特性让它做分组统计特别自然。比如统计每种状态码的占比:

awk '{code[$9]++} END{total=0; for (c in code) total+=code[c]; for (c in code) printf "%s %.2f%%\n", c, code[c]/total*100}' access.log

这种题目已经属于高级范畴,考察的不只是 awk 语法,还有你设计统计流程的思路。建议在纸上画一画:先累加,再遍历,再计算百分比,思路清楚了代码自然就出来了。

4.3 多文件处理与 shell 变量传参

awk 可以一次处理多个文件,而且内置变量FNRNR的区别是面试必问题:

题 60:有两个文件 a.txt 和 b.txt,希望分别打印各自的行号。

awk '{print FILENAME, FNR, $0}' a.txt b.txt

FNR是当前文件内的行号,NR是所有已读入行的总行号。如果文件 A 有 5 行,文件 B 有 3 行,读到 B 的第一行时,FNR是 1,NR是 6。这个区别在合并多个文件做去重时特别重要。

再一个常见场景是 awk 如何接收 shell 变量:

题 68:用 shell 变量 name 作为 awk 的匹配条件,打印包含该变量的行。

name="Alice" awk -v n="$name" '$0 ~ n' file.txt

-v选项可以把外部变量传入 awk,在 awk 内部使用n来引用。如果不加-v,直接写成awk '$0 ~ $name',awk 会把$name理解成第 name 个字段,这是完全不同的含义。还有一个陷阱:如果变量名是FSOFS这种内置变量名,用-v传入会改变 awk 的内置行为,需要特别注意。

awk 的坑多在细节。$0表示整行,$NF表示最后一个字段,这两个符号也经常在题里出现。NF是当前行的字段数量,$NF是取值,两者差一个美元符,含义天差地别。面试时如果把$NF说成“字段数量”,基本就凉了。

5. 综合高频题与易错点:三剑客的组合艺术

5.1 三剑客各司其职的经典套路

实际工作中三剑客很少单独出现,组合使用才是常态。有一道经典综合题:

题 82:从 Nginx 日志中找出返回状态码为 502 的请求,提取出对应的 URL,并统计每个 URL 出现的次数。

这道题需要三个工具协作完成:

grep " 502 " access.log | awk '{print $7}' | sort | uniq -c | sort -rn

grep先过滤出包含 502 的行,awk '{print $7}'提取第 7 列(Nginx 日志默认格式里$7是请求 URL),sort | uniq -c统计每个 URL 的次数,再sort -rn排序。这条命令是“先筛、后取、再统计”思路的典型代表,四个阶段各自由最合适的工具完成。

更复杂的场景是 grep 和 awk 配合做条件过滤。比如筛选出访问次数超过 100 的 IP:

awk '{count[$1]++} END{for (ip in count) if (count[ip]>100) print count[ip], ip}' access.log | sort -rn

这个需求 grep 无法单独完成,因为“次数超过 100”是一个聚合条件,需要 awk 先把数据算出来,再用if判断。这种多阶段处理思路,比单条命令背诵重要得多。

5.2 面试官最爱挖的坑

三剑客的面试题里有很多隐蔽的坑,我总结几个高频出现、学员错误率最高的:

第一个坑是grep -c到底统计什么。grep -c统计的是匹配的行数,而不是匹配的次数。如果一行里出现了 5 次ERRORgrep -c ERROR只会计数 1。想统计出现总次数,要用grep -o ERROR | wc -l-o把每次匹配单独输出一行,再数行数。

第二个坑是 sed 的&符号。在 sed 的替换内容里,&表示“整个匹配到的内容”,所以sed 's/foo/(&)/g'会把所有foo替换成(foo)。如果你确实想替换成字面意义的&,需要写成\&,很多人在替换 XML 实体或包含连接符的文本时踩过这个坑。

第三个坑是 awk 的printprintf混用。print是简化输出,字段之间用OFS(默认空格)连接,自动换行;printf是完全格式化输出,不会自动换行。两者混用时输出会粘在一起,非常容易出错。

第四个坑是正则里的贪婪匹配与非贪婪匹配。grep 和 sed 默认都是贪婪匹配,sed 's/<.*>//g'会把一整段标签内容全部删掉,而不是只删第一个标签。Perl 风格的非贪婪在 grep-P里可以用.*?,但 BRE/ERE 本身没有非贪婪的概念。这个点经常出现在需要清洗 HTML 或配置模板的面试题里。

三剑客组合还有一条通用经验:能用管道解决的问题,不要写复杂的单条命令;反之亦然。管道让数据流清晰可见,每一步都能单独验证,调试成本低很多。我在生产环境里排查问题,基本都是一条一条命令串起来,每步用head看几条输出,确认无误再拼成完整管道。

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

6.1 高频报错与执行结果异常

把我在教学和实际工作中遇到的高频问题整理成了一张速查表:

现象可能原因排查与解决
sed: -e expression #1, char X: unknown option to 's'替换内容中包含了定界符(如/更换定界符,如s#old#new#g
grep: invalid option -- 'r'部分环境 grep 版本或别名导致参数解析异常grep --help查看当前版本支持参数,确认命令格式
awk 输出为空$n中的 n 超出了字段数量范围先用awk '{print NF}' file打印每行字段数
awk 统计结果明显偏大count[$1]++的下标字段选错,比如$1不是预期的 IPawk '{print $1}' file | head查看字段内容
sed 使用-i后文件权限变化部分 sed 实现是通过重写新文件来完成的修改后检查属主和权限,必要时用chmod恢复
grep 匹配中文内容失败系统 locale 未设置为 UTF-8检查LANG环境变量,临时用LANG=en_US.UTF-8

这张表里的问题都是我实际踩过或者学员问过的。第一个“未知选项”几乎每天都能在群里看到,原因极其简单,就是替换内容里有/,但多数人第一反应是“sed 是不是坏了”。所以我把这个排最前面。

6.2 几条压箱底的调试经验

最后分享几个让我少走弯路的经验,都是文档里不会写的东西。

第一,调试时永远先不加-i。无论 sed 还是其他修改文件的命令,先让结果输出到终端,肉眼确认后再加上-i。很多人在-i后才发现替换结果不对,原文件已经改坏了,只能从备份里恢复。如果有备份还好,没有备份就只能干瞪眼。

第二,awk 脚本从简单开始,逐步加条件。我见过太多人一上来就写一个庞大的 awk 脚本,报错了却不知道是哪一步出了问题。正确的做法是:先用awk '{print $1}'看看字段对不对,再加匹配条件,再加上统计逻辑,最后加格式化输出。每一步都验证,比整体调试高效得多。

第三,用好head和管道配合。处理超大日志文件时,别一上来就全量跑,先用head -100 file | 你要调试的命令,确认逻辑没问题再全量执行。这个习惯能帮你省下大量等待时间,也能避免一条错误命令在全量文件上产生毁灭性影响。

第四,grep、sed、awk 不是互相替代的关系。很多人在掌握了 awk 之后,恨不得所有文本处理都用 awk 搞定。实际上,能一条 grep 解决的事情就不要写一段 awk,能一条 sed 完成的事就不要引入数组。命令越简单,出错概率越小,别人接手也更容易看懂。这一点我觉得比掌握所有高级语法更重要。

第五,面试时如果被问到不会的题目,不要直接说不会。把你能想到的方向说清楚,比如“这个需求我会用 awk 的数组来统计,但是具体输出格式我需要再确认一下”,面试官至少知道你有解题思路。三剑客本质上都是工具,思路清晰的人就算某个参数记不准,看一眼 man page 也能写出来;思路混乱的人就算背了一百道题,碰到新场景还是懵。这也是我整理这套题库时最强调的部分。

这套 100 道题覆盖的知识点足够应对绝大多数 Linux 岗位面试了,但请你记住,背答案只是底线,能把每条命令拆开讲清楚为什么,才是真正的分水岭。希望你刷完题后,不只是“见过”,而是真正“会用”。

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

双框架实践:ThinkPHP+Laravel构建口腔门诊管理系统

口腔门诊管理系统这类型的项目&#xff0c;在毕业设计和中小型外包里出现频率非常高。但大多数网上能搜到的所谓“源码”都存在一个问题&#xff1a;要么是单纯的增删改查demo&#xff0c;要么业务逻辑根本撑不起真实门诊的运转。这段时间我把一套基于ThinkPHP和Laravel双框架实…

作者头像 李华
网站建设 2026/9/9 19:51:58

LVM存储与K8s PV/PVC/StorageClass核心概念详解

做运维的人应该都有过这种经历&#xff1a;某个业务目录空间告急&#xff0c;df一看已经 97%&#xff0c;头开始大。如果这套环境用的是传统分区&#xff0c;那接下来的剧本往往是“停机、加磁盘、迁移数据、重新挂载”&#xff1b;如果当初用了 LVM 逻辑卷&#xff0c;情况就会…

作者头像 李华
网站建设 2026/9/9 19:50:38

GENESIS细胞结构建模:从SWC数据到多房室神经元仿真

GENESIS系列写了好几篇&#xff0c;之前一直在聊通道动力学、突触机制这些偏“功能”的东西。这次第七篇&#xff0c;我打算回头把基础打牢&#xff0c;专门讲细胞结构建模。为什么要专门写这个&#xff1f;因为我发现很多刚开始玩GENESIS的人&#xff0c;喜欢一上来就堆channe…

作者头像 李华
网站建设 2026/9/9 19:48:19

【JAVA课程设计/毕业设计】基于SpringBoot的智能在线学习交流平台的设计与实现 基于SpringBoot的师生在线学习交流系统的设计与实现【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华