1. 先把“模式”这两个字吃透很多人学 awk 是背命令awk {print $1}、awk -F: {print $3}这么一条条记记到后面记混了一遇到“只要第 3 行到第 10 行”“只要字段里带 error 的行”就卡住。我当初也是这样真正让 awk 用起来顺手的转折点是把pattern模式这个概念的层级想明白了awk 不是“打印某一列”的工具它是“逐行扫描 条件筛选 动作执行”的流水线而“模式”就是这条流水线上那道闸门闸门开不开、开多久全由模式决定。这篇文章聊的就是这道闸门——awk 的常用匹配模式。awk 的全称是 Aho、Weinberger、Kernighan 三人姓氏缩写1977 年成型到今天依然是各类 Unix 系系统里默认装着的文本处理工具之一几乎任何一个能跑 shell 的环境都有它。它能做什么一句话概括按行读、按字段拆、按你给的条件判断、按你写的动作输出中间还能累加、去重、排序、格式化。它解决的问题是“把一段有规律的文本快速变成另一段有规律的文本”。适合谁来读写过几条 Linux 命令、被 awk 的$1、$NF弄得有点懵想让自己的脚本从“能用”变成“稳、快、好维护”的那批人。零基础也能跟上我会把每个模式的意图和踩坑点都拆开讲不假设你已经背熟了语法表。先给一个最关键的心智模型后面所有内容都建立在它上面awk 模式 { 动作 } 文件这条语句读起来是“对每一行如果这一行满足‘模式’就执行‘动作’”。模式可以省略省略时对每一行都执行动作动作也可以省略省略时默认动作是print $0即打印整行。这里最容易忽略的一点是模式不是“过滤器的附属品”它和动作是对等的两个半区/error/、NR10、$3GET、BEGIN、/start/,/end/全都属于“模式”这一个位置的合法取值。理解到这一层你就不会再把 awk 当成“带条件的 print”了。1.1 一条 awk 语句的执行顺序比语法更重要我建议每个刚上手的人都先把执行顺序在脑子里跑一遍因为它直接决定了很多“看起来莫名其妙”的现象。awk 处理输入的过程是这样的先执行所有的BEGIN块可以有好几个按书写顺序然后开始循环——读一条记录按FS切成字段依次测试每一个“模式 动作”对命中的执行动作全部测试完再读下一条记录直到输入读完最后执行END块。这个顺序解释了三件事为什么BEGIN里能初始化变量而不用等数据为什么在动作里改了$2后面的print $0会跟着变字段被赋值后整条记录会按OFS重建为什么END里能放心地打印累加结果。注意BEGIN块里的FS赋值会影响第一条记录的切分这是极少数“在数据读入前必须做完”的设置而如果你在普通动作块里写FS:它只影响下一条记录当前这条已经是切好的了这个坑我见过不止一个人踩。还有一个容易忽视的点多个“模式 动作”对之间是并列关系不是 if-else。同一行可以同时命中三个模式三个动作都会执行。想让后面的不再执行得靠next或exit主动跳出去。这个特性在写“默认打印 特殊情况特殊处理”的逻辑时特别好用但也是造成“输出重复了好几遍”的常见原因。1.2 不同实现的差异得先摸清楚awk 有几个常见实现gawkGNU 版功能最全、mawkDebian 系默认轻快、busybox awk精简环境里常见、以及某些系统上的nawk。日常的匹配模式这几个实现都能跑但边界处差别不小我列几个真会咬人的特性gawkmawkbusybox awkIGNORECASE忽略大小写支持不支持部分支持区间量词{n,m}默认开支持视版本FPAT按字段内容切分支持不支持不支持nextfile支持支持较新版本支持--csv直接吃 CSV5.1 支持不支持不支持数组遍历顺序可PROCINFO[sorted_in]控制不可控不可控这张表的意义不在于让你背而在于提醒写可移植脚本时别依赖IGNORECASE老老实实用tolower($0) ~ /error/需要按列数、按内容切字段时先确认目标机器上到底是哪个 awkawk --version或ls -l $(which awk)看软链。我自己吃过一次亏在开发机上用IGNORECASE1写得舒服部署到一台精简容器里版本不认识这个变量直接当成空值忽略结果大小写混着的数据全漏了排查了半小时才发现是“变量被静默忽略”而不是“正则写错”。2. 常用匹配模式的分类与选型2.1 五类模式一张表理清awk 的模式位置能放的东西不算多我把它们归成五类这是我认为最好记的分法类别写法示例触发条件典型用途特殊模式BEGIN、END处理前 / 全部处理完初始化、汇总输出表达式模式NR1、$3100、NF5表达式值为真非 0 非空按行号、字段值筛选正则模式/error/、$0 ~ /^2024/正则匹配成功关键字、格式筛选范围模式/BEGIN/,/END/从匹配起点到匹配终点抓取区块组合模式/error/ $2POST布尔组合为真多条件精确筛选这张表里最值得多说一句的是“表达式模式”的真假判定规则。awk 里数字 0 为假空字符串为假其他都为真。麻烦的地方在于“看起来像数字的字符串”awk 有个 strnum 概念从输入里读出来的字段如果长得像数字比较时会按数字比而字符串常量按字符串比。所以$1 10和$1 10在边界上结果可能不同9 10是字符串比较结果为真因为9 19 10是数字比较结果为假。我在按大小筛日志里的耗时字段时踩过这个坑$NF 100结果冒出一堆 9 毫秒的记录原因就是那一列混了非数字内容awk 退化成字符串比较了。稳妥的写法是先做一次数值转换($NF0) 100加个0强制转数字语义清晰也不会被脏数据带偏。2.2 选型的判断顺序我一般这么走拿到一个筛选需求我的判断顺序是固定的能按行号 / 字段数定位的优先用表达式别上正则。行号和字段数是结构性信息判断成本低也不会因为内容里恰好出现某个词而误伤需要按键字或格式匹配的用正则常量需要跟某个字段比对内容而不是整行比对的用~锚到具体字段需要抓一段区间的才用范围模式最后任何需要前后各做一次的场景套BEGIN/END。举个具体例子说明这个顺序的价值。要从一份访问日志里取“第 2 列是某个接口名、且状态码是 5 开头”的记录。新手容易写成awk /api/ /5[0-9][0-9]/问题在于整行里任何位置出现 5 开头的三位数都会命中比如响应体长度 500、时间戳里的 500。按字段锚定就干净了awk $2 ~ /api/ $9 ~ /^5[0-9][0-9]$/。后者的可读性和抗干扰能力都高一个量级代价只是多敲几个字符。这类“锚定到字段”的习惯是我建议从第一天就养成的。3. 逐个拆解高频匹配模式的写法与坑3.1 BEGIN 与 END把“前后各一次”用到位BEGIN和END是两种不带输入匹配的特殊模式BEGIN在读取任何数据之前执行END在全部数据读完之后执行。它们的价值不在语法而在把“一次性动作”从“每行动作”里剥离出来。最常见的用法有三类一是设置分隔符和输出格式比如BEGIN{FS,; OFS\t}二是初始化累加变量虽然 awk 里未定义变量默认就是/0但显式写出来可读性更好三是在END里输出汇总比如计数、求和、求平均。# 统计状态码为 5xx 的请求数并输出占比 awk BEGIN { FS ; total 0; bad 0 } { total } $9 ~ /^5[0-9][0-9]$/ { bad } END { if (total 0) printf total%d bad%d rate%.2f%%\n, total, bad, bad * 100 / total else print no input } access.log这段代码里的if (total 0)是必须的。输入为空时total是 0直接做除法会抛出一个运行时警告gawk 下输出类似division by zero attempted结果为inf而不是让你安静地拿到 0。这种“空输入保护”在写自动化脚本时尤其重要因为脚本跑在定时任务里没人盯着看报错结果文件里静悄悄多出一行rateinf才是最难受的。还有个细节BEGIN和END可以写多个按出现顺序执行。我有时会把“参数校验”和“格式设置”分成两个BEGIN块逻辑上更清楚。END里能访问所有的累加变量但如果中途用exit提前跳出END依然会执行——这一点非常有用比如某个文件读到第一万行就够用了exit之后在END里统一输出不用在中间写重复的输出逻辑。反过来如果你的exit是想彻底终止、连END都不跑那就得自己加个标志变量在END里判断这是少数必须记住的例外。3.2 表达式模式最稳、最快、最该优先用表达式模式是模式位置放一个求值表达式结果为真就执行动作。它覆盖面极广行号判断NR1、NR%20、字段数判断NF5、NF0、字段值比较$3GET、$401.5、算术组合(NR-1)%1000每百行取一条都能写。相比正则它的优势是明确指向结构而非内容不受数据内容干扰执行也更快。几个我高频使用的表达式模式值得单独记awk NR 1 file # 跳过表头 awk NF 0 file # 跳过空行注意 NF 对空行的判定 awk NR % 2 1 file # 取奇数行 awk NRFNR{next} {print} a b # 用第一个文件做过滤白名单第二个文件做输出 awk length($0) 80 file # 按整行长度筛选NRFNR{next}这个写法值得展开讲它是 awk 里处理“两个文件关联”的经典套路。原理是NR是累计行号FNR是当前文件内的行号读第一个文件时两者相等读第二个文件时NR已经大于FNR。所以NRFNR成立时说明正在处理第一个文件next表示跳过后续所有模式动作进入下一行。这个套路的坑在于第一个文件必须非空——如果第一个文件是空的NRFNR在第二个文件的第一行会短暂成立都是 1导致第一行被误跳过。我一般会在前面加一句防护或者干脆用ARGINDgawk 特有来避免。提示NF 0和length($0) 0不是一回事。如果FS是单个空格一行全是空格的情况下NF是 0但整行长度不为 0。用哪个取决于你是不是要把“纯空白行”也算作空。我处理日志时倾向用NF 0因为它更符合“有没有实际字段”的语义。3.3 正则模式常量、锚定字段、动态构造正则模式是 awk 最常被使用、也最容易写错的一类。它有两种形态正则常量/pattern/和匹配操作符表达式 ~ /pattern/。前者等价于$0 ~ /pattern/也就是拿整行去比后者可以指定任意表达式最常见的用法是锚定到某个字段$3 ~ /pattern/或者用变量动态构造$0 ~ key。先讲一个几乎人人都会遇到的问题正则元字符的处理。.匹配任意字符*?是量词[]是字符集^$是锚点()|是分组和或{}是区间量词\是转义。要匹配字面量的点必须写\.要匹配字面量的斜杠在/.../常量里要写\/。我见过最常见的误写是拿 IP 地址或版本号直接当正则比如/1.2.3/本来以为只匹配 “1.2.3”结果把 “1x2y3” 也匹配上了。这种时候要么转义成/1\.2\.3/要么改用字段精确比较$11.2.3。然后是锚点。/error/会匹配 “no error here”/^error/才只匹配行首。做日志筛选时锚点几乎是必需品因为关键字往往出现在非预期位置。同理$锚行尾$9 ~ /^5[0-9][0-9]$/这种写法能避免把 “5000” 误判为 5xx 状态码。字符集里的^是取反[^0-9]表示非数字这个和锚点的^是两套语义位置不同含义完全不同别混。动态正则是个进阶但很好用的能力模式部分可以是个表达式只要结果是个字符串就当正则用。比如从外部传进来一个关键字-v keyerror然后写$0 ~ key。这让同一份脚本能适配不同的筛选目标不必每次改代码。需要注意两点一是关键字里如果含有正则元字符会被当正则解释如果需要字面匹配得先做转义gawk 里有gensub可以用或者用index($0, key) 0做纯字符串查找二是~右边的表达式求值发生在每一行如果构造过程复杂会拖慢性能能提到BEGIN里预先算好的就别放在动作里。3.4 范围模式抓一段区间但要知道它怎么结束范围模式写成/起点/,/终点/含义是“从匹配起点的行开始一直到匹配终点的行结束全都命中”。它在抓配置段、抓代码块、抓某段日志时非常顺手# 抓取配置文件中某个段落 awk /^\[database\]/,/^\[/ config.ini # 抓取某次请求前后的日志 awk /request id: 7f3a/,/request end/ app.log用范围模式有一个必须记住的行为它的两端是“行级”判定起止可以出现在同一行。如果某一行同时匹配起点和终点这一行会被输出然后范围立即结束下一行就不在范围内了。这在抓“单行成对”的场景下会让人困惑——比如日志里一行同时有begin和end你以为抓到了整段实际上只抓到了这一行。另一个更隐蔽的行为是范围模式一旦启动就不会因为起点再次出现而重启它会一路走到终点匹配为止如果终点始终没出现它会一直输出到文件末尾。这个特性在抓日志时经常导致“多抓了后面一大片”尤其是终点关键字在文件里根本不存在的情况下。我一般的做法是抓之前先用grep -c确认起点和终点的出现次数是否匹配或者在END里检查一下有没有“未闭合”的情况输出个提醒。还有个小技巧范围模式的两端都可以是任意“模式”不一定是正则。比如NR10,NR20就是取第 10 到 20 行/start/,0这种写法用常量 0 当终点等于“从 start 开始一直到文件末尾”因为 0 永远为假终点永不匹配。这个写法比写复杂的结束条件省事我在做“取某个标记之后的全部内容”时经常用。3.5 特殊变量与文件切换让模式判断有依据模式要判断得有依据awk 提供的内置变量就是这批依据。最常用的几个NR总行号、FNR当前文件行号、NF字段数、$0整行、$n第 n 个字段、FILENAME当前文件名、ARGIND当前文件序号gawk、RSTART/RLENGTH配合match()用。此外还有几个影响读入行为的FS输入字段分隔符、RS输入记录分隔符、OFS输出字段分隔符、ORS输出记录分隔符、SUBSEP多维数组下标分隔符。这里面FS的规则值得专门讲因为它是“分隔符匹配”这件事的核心。规则有三条默认值是一个空格此时 awk 会把连续的空格和制表符都当作一个分隔符并且忽略行首空白——这是唯一“特殊对待”的取值设成单个字符如FS:时按该字符切分连续两个冒号会产生一个空字段设成多字符字符串如FS::时按字面整体匹配设成正则如FS[ \t]时按正则切分。我在处理 CSV 之外的变长空白分隔文件时一定写FS[ \t]而不是留着默认值——因为默认值对制表符和空格的混合处理虽然也能用但在跨平台拷贝、行尾有\r的情况下容易出现字段数对不上。RS用得少但威力大。默认按换行切记录把RS设成空字符串会进入“段落模式”空行作为记录分隔符适合处理那种一段一段的文本设成某个特殊字符串就能按自定义分隔符切记录比如按/entry切 XML 片段。RS的坑在于它和FS的联动切完记录之后字段是按FS在这条记录内部切的如果记录里带换行而FS又是默认的空格字段会被换行切开导致$1的语义和你想的不一样。这种时候要么改FS要么先用gsub把换行处理掉。4. 完整实操从一份服务日志里捞出想要的数据光讲模式还是虚得有个能跑通的完整链路。下面这份场景是纯虚构的模拟示例但结构和真实日志很接近我按“看清结构 → 分段构建条件 → 补输出 → 封装复用”四步走一遍。4.1 先看清数据结构别急着写正则假设日志长这样空格分隔字段依次是时间、级别、模块、请求方法、路径、状态码、耗时毫秒2024-05-11T09:00:01 INFO gateway GET /api/order/list 200 35 2024-05-11T09:00:02 WARN gateway POST /api/order/create 500 1203 2024-05-11T09:00:03 INFO cache GET /api/user/profile 200 8 2024-05-11T09:00:04 ERROR gateway GET /api/order/detail 503 3011第一步永远是数清楚字段而不是直接写$5。我习惯用awk {print NF} file | sort -u看一眼字段数是否稳定再用awk NR3{for(i1;iNF;i) print i, $i} file把前几行的字段逐个打出来对照。这一步花 30 秒能省掉后面 30 分钟的“为什么取错了列”。如果字段数不稳定比如路径里带空格就得考虑改用固定分隔符或者用FPATgawk按内容模式切分而不是硬套空格分隔。4.2 分段构建匹配条件别一次写完需求定为找出“状态码是 5 开头、耗时超过 1000 毫秒、路径是/api/order前缀”的记录。我不会一次写出完整命令而是分段叠加每加一个条件就看一眼输出量级是否合理# 第一步只筛状态码 5xx awk $6 ~ /^5[0-9][0-9]$/ app.log # 第二步叠加耗时阈值注意 0 强制数值比较 awk $6 ~ /^5[0-9][0-9]$/ ($7 0) 1000 app.log # 第三步叠加路径锚定注意 ^ 锚在路径开头 awk $6 ~ /^5[0-9][0-9]$/ ($7 0) 1000 $5 ~ /^\/api\/order/ app.log第三步里\/的转义容易看漏。在/.../正则常量里斜杠必须转义否则会提前结束正则。另一个选择是把路径前缀放进变量用字符串比较更省心substr($5, 1, 10) /api/order可读性更好也完全避开了正则转义。这种“能用字符串比较就别上正则”的取舍我在处理固定前缀时一律这么选。为什么要分段因为一次性写长条件一旦输出为空你根本不知道是哪一段把它卡死了。分段之后每一步的输出条数就是天然的中间检验点这个方法我用了很多年比事后print调试高效得多。4.3 输出与格式化让结果能直接给人看筛出来只是开始输出格式往往决定这份结果能不能直接用。我会用printf控制列宽和对齐并在前后加上汇总awk BEGIN { FS [ \t]; OFS \t; count 0; sum 0 } $6 ~ /^5[0-9][0-9]$/ ($7 0) 1000 $5 ~ /^\/api\/order/ { count sum $7 printf %-19s %-6s %-8s %-4s %-20s %s\n, $1, $2, $3, $6, $5, $7 } END { if (count 0) printf ---- matched%d avg_cost%.1fms max_cost tracked below ----\n, count, sum / count else print ---- no matched record ---- } app.log这里FS [ \t]而不是默认值是为了容忍日志里可能出现的不规则空白OFS \t配合手写printf其实用途不大但在同时用print输出其他行的混合脚本里就很重要了因为print $1, $2会用OFS拼字段。%-19s这类左对齐宽度是我固定使用的写法宽度按最长时间戳的长度定改格式时只改一处。一个实测有效的经验printf里不要用变量拼格式串比如printf fmt, $1这种写法如果fmt来自外部输入且含有%会引发意料之外的格式解析甚至安全风险。格式串永远写成字面量需要动态宽度的用*传参printf %*s\n, width, $1。这个细节看起来小但在写会被别人复用的脚本时相当关键。4.4 封装成可复用脚本参数外置一次性命令的寿命通常很短第二天就想不起来当时怎么写的。我的习惯是把高频筛选逻辑固化成脚本把变化的部分做成参数用-v传进去#!/bin/sh # 用法./scan.sh app.log 500 1000 /api/order set -eu file$1 code_prefix${2:-5} min_cost${3:-1000} path_prefix${4:-/api} awk -v code$code_prefix -v cost$min_cost -v path$path_prefix BEGIN { FS [ \t]; n 0 } $6 ~ (^ code [0-9][0-9]$) ($7 0) cost index($5, path) 1 { n printf %-19s %-6s %-8s %s\n, $1, $2, $6, $5 } END { printf matched%d\n, n } $file这里有两个细节值得说。第一动态正则用(^ code [0-9][0-9]$)拼接code是纯数字所以拼接安全如果参数可能含正则元字符就别拼正则改用substr判断前缀。第二index($5, path) 1比$5 ~ ^ path更安全它是纯字符串查找path里有.或/都不会被当元字符解释这个替换在参数来自外部时几乎是必须的。set -eu是 shell 层的防护避免脚本在变量拼错时拿着空值继续跑。5. 常见问题与排查速查5.1 正则写对了但匹配不上先查这四处匹配失败的案例里九成以上不是正则语法问题而是“看起来同一个东西其实不是”。我按排查频率排个序现象可能原因快速验证处理方式明明有该字段却匹配不上行尾有\rWindows 换行awk {print length($0)}看是否比预期长sub(/\r$/, )或读入前dos2unix字段数比预期多FS不是你以为的那个awk -F {print NF; exit}显式-F或BEGIN{FS...}大小写混着就漏了没做大小写统一对比~ /error/和~ /Error/tolower($0) ~ /error/关键字里含元字符.(被当语法换成index()试转义或改字符串比较第一行那个\r的问题我在跨系统拷文件时遇到过太多次。现象是“肉眼看着一模一样正则就是不匹配”因为\r是不可见字符通常跟在行尾最后一个字段后面导致$NF ~ /error$/失败。最快的验证是awk END{print length($0)}对比预期长度或者cat -A看行尾有没有^M。还有一个高频误解是“/pattern/会匹配所有字段”。它只匹配$0整行如果那一行被FS切成了多段整行里仍然包含分隔符所以/a b/在FS 的情况下确实能命中两个相邻字段的边界看起来很神奇实际上是整行字符串匹配的结果。理解这一点之后/foo/和$1 ~ /foo/的区别就不会再混了。5.2 变量、引号与转义脚本里最容易翻车的地方awk 脚本通常被单引号包在 shell 里这就形成了两层转义shell 一层awk 一层。我列几条实战中反复出现的# 错单引号里想用 shell 变量结果原样传给 awk awk {print $$col} file # 对用 -v 传语义清楚 awk -v c$col {print $c} file # 对需要 awk 内部识别为数字注意 -v 的数值转换 awk -v n$num BEGIN{ if (n 0 10) print big }用-v传值有个隐含行为gawk 的-v会处理反斜杠转义比如-v sa\tb会变成真正的制表符而通过ARGV或环境变量传入的不会。这个差异在传包含路径或正则的值时会造成困惑。如果不想被转义处理影响用ENVIRON读环境变量是个干净的办法k$KEY awk BEGIN{ if (ENVIRON[k] ~ /x/) ... }注意这里ENVIRON拿的是字符串原值不经过转义加工。另一个隐蔽的坑是$在 shell 里的展开。awk 的$1、$NF在单引号里是安全的但一旦你为了插值把脚本拆成双引号拼接$1就会被 shell 当成位置参数展开变成空字符串于是print后面跟了个孤零零的。这类问题的特点是“不报错只是输出不对”排查起来很费时间。我的习惯是awk 脚本一律单引号整体包裹需要外部值全部走-v从不拼接。5.3 性能与内存什么时候该换工具awk 处理几百 MB 的文本毫无压力但有几个写法会让它明显变慢。第一是“在动作里反复执行同样的正则匹配”比如循环里对同一个字段多次~ /.../第二是“用$0整行匹配代替字段锚定”整行匹配的字符串更长正则引擎的工作量更大第三是“在END里做本该边读边算的事”把全部数据存进数组再处理内存会随行数线性增长。大文件场景下我一般会做这几件事设LC_ALLC让字符串比较走字节而非多字节字符集实测在纯 ASCII 数据上有可观提速用next尽早短路把最可能命中的、最便宜的条件写在前面让后面的判断直接被跳过需要去重时用关联数组但注意数组键的数量如果唯一值有几百万个内存会吃紧这时候sort -u可能更合适。至于“什么时候不该用 awk”我的判断标准是需要复杂的分组聚合再排序输出用sortawk管道通常比纯 awk 数组清爽需要解析严格嵌套的结构JSON、XML用专门的解析工具别拿正则硬啃这类需求用 awk 写出来的东西过两周自己都看不懂需要逐行调用外部命令的那个外部命令的开销会盖过 awk 本身的优势不如换个思路。6. 几个我踩过坑之后固化下来的习惯写 awk 这些年语法记不全不要紧man awk随时能查但有几种习惯是真正影响产出的。第一个习惯是先确认数据形状再写模式。NF的分布、行尾有没有\r、分隔符是不是真的单空格这三项检查花不到一分钟但能挡掉后面大半的“为什么不对”。我现在写任何一段超过两行的 awk都会先跑一次awk {print NF} file | sort | uniq -c看一眼字段数稳不稳定稳了再动手。第二个习惯是条件永远锚定到字段不锚到整行。$6 ~ /^5/永远比/5[0-9][0-9]/可靠因为你知道它在看哪一列。整行匹配只在“真的想在任何位置找关键字”时用比如全文搜索某个错误码。这条习惯让我少写了大量的调试时间代价只是多敲几个字符。第三个习惯是把BEGIN当成“配置区”。FS、OFS、阈值、格式化前缀、正则变量全都在BEGIN里声明清楚。这样脚本读起来像一份配置加一段逻辑别人接手时不用满篇找“这个变量在哪赋的值”。而且BEGIN里声明的FS对第一条记录生效这个行为上的确定性本身就值得依赖。第四个习惯是给每个END加空输入保护。除法、max/min的初值、数组遍历的输出只要输入可能为空就在END开头判断一下计数。定时任务里跑出inf或nan没人会立刻发现等到有人看报表时才回头查成本高得多。最后说一个容易被忽略的扩展方向把常用模式沉淀成函数。gawk 支持自定义函数把“判断是否 5xx”“判断路径前缀”“格式化耗时”写成函数主逻辑会变得很短也方便在多份脚本之间复用。函数里的参数是值传递数组是引用传递return一个布尔值就能当模式用这个写法在我维护的那几个日志分析脚本里已经成了标配改动一处、全部生效比复制粘贴强太多。
阅读完成 · 觉得有帮助?