AWK 教程:Linux 中 AWK 命令的 25 个实用示例 您所在的位置:网站首页 awk字符串切割并打印 AWK 教程:Linux 中 AWK 命令的 25 个实用示例

AWK 教程:Linux 中 AWK 命令的 25 个实用示例

2024-06-03 12:18| 来源: 网络整理| 查看: 265

AWK 教程:Linux 中 AWK 命令的 25 个实用示例

想知道如何在 Linux 中使用 AWK 命令?这里有 25 个 AWK 命令示例以及正确的解释,将帮助您掌握 AWK 的基础知识。

AWK 命令可以追溯到早期的 Unix 时代。它是 POSIX 标准的一部分,应该可以在任何类 Unix 系统上使用。超越。

虽然 AWK 有时因其年代久远或与 Perl 等多用途语言相比缺乏功能而受到质疑,但它仍然是我在日常工作中喜欢使用的工具。有时是为了编写相对复杂的程序,但也因为您可以编写强大的单行代码来解决数据文件的问题。

所以,这正是本文的目的。向您展示如何在不到 80 个字符的时间内利用 AWK 的强大功能来执行有用的任务。本文无意成为完整的 AWK 教程,但我仍然在开头包含了一些基本命令,因此即使您以前几乎没有经验,您也可以掌握核心 AWK 概念。

我的本 AWK 教程的示例文件

该文章中描述的所有单行代码都将在同一数据文件上进行测试:

cat file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

您可以在 GitHub 上在线获取该文件的副本。

了解 AWK 中的预定义变量和自动变量

AWK 支持一些预定义和自动变量来帮助您编写程序。其中你会经常遇到:

RS –记录分隔符。 AWK 一次处理一条记录的数据。记录分隔符是用于将输入数据流分割成记录的分隔符。默认情况下,这是换行符。因此,如果不更改它,一条记录就是输入文件的一行。

NR – 当前输入记录编号。如果您对记录使用标准换行符分隔符,则它与当前输入行号匹配。

FS/OFS –用作字段分隔符的字符。一旦 AWK 读取一条记录,它就会根据FS 的值。当 AWK 在输出上打印记录时,它将重新连接字段,但这次使用 OFS 分隔符而不是 FS 分隔符。通常,FS 和 OFS 是相同的,但这不是强制性的。 “空白”是两者的默认值。

NF – 当前记录中的字段数。如果您在字段中使用标准“空白”分隔符,则这将与当前记录中的字数匹配。

还有其他或多或少标准的 AWK 变量可用,因此值得检查特定的 AWK 实现手册以获取更多详细信息。然而,这个子集已经足以开始编写有趣的俏皮话了。

AWK命令的基本用法1. 打印所有行

这个例子基本上没什么用,但它仍然是 AWK 语法的一个很好的介绍:

awk '1 { print }' file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

AWK 程序由一个或多个 pattern { action } 语句组成。

如果对于输入文件的给定记录(“行”),模式计算结果为非-零值(相当于AWK中的“true”),执行相应操作块中的命令。在上面的示例中,由于 1 是非零常量,因此会对每个输入记录执行 { print } 操作块。

另一个技巧是 { print } 是 AWK 将使用的默认操作块(如果您没有明确指定)。所以上面的命令可以缩短为:

awk 1 file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

几乎同样无用的是,以下 AWK 程序将消耗其输入,但不会产生任何输出:

awk 0 文件

2. 删除文件头awk 'NR>1' file 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

请记住,这相当于显式编写:

awk 'NR>1 { print }' file 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

该单行代码将写入输入文件的记录(第一个记录除外),因为在这种情况下,条件为 1>1 ,这显然不成立。

由于该程序使用 RS 的默认值,因此实际上它将丢弃输入文件的第一行。

3. 打印一定范围内的行

这只是前面示例的概括,不需要太多解释,除了说 && 是逻辑 and 运算符:

awk 'NR>1 && NR < 4' file 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team4. 删除仅空白的行awk 'NF' file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

AWK 根据 FS 变量中指定的字段分隔符将每个记录拆分为字段。默认字段分隔符是一个或多个空白字符(也称为空格或制表符)。通过这些设置,任何包含至少一个非空白字符的记录都将包含至少一个字段。

换句话说,NF 为 0(“假”)的唯一情况是记录仅包含空格。因此,这一行只会打印包含至少一个非空格字符的记录。

5.删除所有空行awk '1' RS='' file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

这个单行基于一个晦涩的 POSIX 规则,该规则指定如果 RS 设置为空字符串 ,那么记录将由由 加组成的序列分隔一个或多个空行。 ”

值得一提的是,在 POSIX 术语中,空行是完全空的行。仅包含空格的行不算作“空白”。

6. 提取字段

这可能是 AWK 最常见的用例之一:提取数据文件的某些列。

awk '{ print $1, $3}' FS=, OFS=, file CREDITS,USER 99,sylvain 52,sonia 52,sonia 25,sonia 10,sylvain 8,öle , , , 17,abhishek

在这里,我明确地将输入和输出字段分隔符设置为逗号。当 AWK 将记录拆分为字段时,它将第一个字段的内容存储到 $1,第二个字段的内容存储到 $2,依此类推。我在这里不使用它,但值得一提的是 $0 是整个记录。

在这段话中,您可能已经注意到我使用了一个没有模式的动作块。在这种情况下,模式假定为 1(“true”),因此针对每个记录执行操作块。

根据您的需要,它可能不会产生我们想要的空白或仅空白行。在这种情况下,第二个版本可能会更好一些:

awk 'NF { print $1, $3 }' FS=, OFS=, file CREDITS,USER 99,sylvain 52,sonia 52,sonia 25,sonia 10,sylvain 8,öle , 17,abhishek

在这两种情况下,我都在命令行上传递了 FS 和 OFS 的自定义值。另一种选择是在 AWK 程序中使用特殊的 BEGIN 块在读取第一条记录之前初始化这些变量。因此,根据您的口味,您可能更喜欢这样写:

awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file CREDITS,USER 99,sylvain 52,sonia 52,sonia 25,sonia 10,sylvain 8,öle , 17,abhishek

值得一提的是,您还可以使用 END 块在读取最后一条记录后执行一些任务。就像我们现在就会看到的那样。话虽这么说,我承认这远非完美,因为纯空白行的处理并不优雅。我们很快就会看到一个可能的解决方案,但在此之前让我们做一些数学计算……

7. 按列执行计算

AWK 支持标准算术运算符。并会根据上下文自动在文本和数字之间转换值。此外,您还可以使用自己的变量来存储中间值。所有这些都允许您编写紧凑的程序来对数据列执行计算:

awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file 263

或者,等效地使用 += 简写语法:

awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file 263

请注意 AWK 变量在使用前不需要声明。假定未定义的变量保存空字符串。根据AWK类型转换规则,它等于数字0。由于该功能,我没有费心显式处理 $1 包含文本(在标题中)、空格或仅包含任何内容的情况。在所有这些情况下,它都会算作 0 并且不会干扰我们的求和。当然,如果我改为执行乘法,结果会有所不同。那么,您为什么不使用评论部分针对这种情况提出解决方案呢?

8. 统计非空行的数量

我之前已经提到过 END 规则。这是另一个可能的应用程序来计算文件中的非空行数:

awk '/./ { COUNT+=1 } END { print COUNT }' file 9

在这里,我使用了 COUNT 变量,并为匹配正则表达式 /./ 的每一行递增该变量 (+=1)。即每一行至少包含一个字符。最后,END 块用于在处理整个文件后显示最终结果。 COUNT 这个名称没有什么特别之处。我可以使用 Count、count、n、xxxx 或任何其他符合 AWK 变量命名规则的名称

然而,这个结果正确吗?嗯,这取决于您对“空”行的定义。如果您认为只有空行(根据 POSIX)是空的,那么这是正确的。但也许您更愿意将仅包含空白的行也视为空行?

awk 'NF { COUNT+=1 } END { print COUNT }' file 8

这次结果有所不同,因为后来的版本也忽略了仅空白的行,而初始版本仅忽略了空白行。你能看到区别么?我让你自己想办法。如果这还不够清楚,请不要犹豫使用评论部分!

最后,如果您只对数据行感兴趣,并且考虑到我的特定输入数据文件,我可以这样写:

awk '+$1 { COUNT+=1 } END { print COUNT }' file 7

它之所以有效是因为 AWK 类型转换规则。模式中的一元加号强制在数字上下文中对 $1 求值。在我的文件中,数据记录的第一个字段中包含一个数字。非数据记录(标题、空行、仅空白行)包含文本或不包含任何内容。转换为数字时全部等于 0。

请注意,使用最新的解决方案,最终拥有 0 积分的用户的记录也将被丢弃。

B. 在 AWK 中使用数组

数组是 AWK 的一个强大功能。 AWK 中的所有数组都是关联数组,因此它们允许将任意字符串与另一个值关联。如果您熟悉其他编程语言,您可能知道它们为哈希、关联表、 字典或地图。

9.AWK数组的简单例子

假设我想知道所有用户的总信用额。我可以在关联数组中为每个用户存储一个条目,每次遇到该用户的记录时,我都会增加数组中存储的相应值。

awk '+$1 { CREDITS[$3]+=$1 } END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file abhishek 17 sonia 129 öle 8 sylvain 109

我承认这不再是一句俏话。主要是因为 for 循环用于在处理文件后显示数组的内容。那么,现在让我们回到更简短的例子:

10.使用AWK识别重复行

与其他 AWK 变量一样,数组既可以在操作块中使用,也可以在模式中使用。利用这一点,我们可以编写一行代码来仅打印重复的行:

awk 'a[$0]++' file 52,01 dec 2018,sonia,team

++ 运算符是从 C 语言家族继承的后置自增运算符(AWK 是 C 语言家族的骄傲成员,这要归功于其原始作者之一的 Brian Kernighan)。

顾名思义,后递增运算符会递增(“加 1”)变量,但仅在将其值用于 englobing 表达式的求值之后。

在这种情况下,将评估a[$0]以查看是否将打印记录,并且一旦做出决定,在所有情况下,数组条目都会递增。

因此,第一次读取记录时,a[$0] 未定义,因此对于 AWK 来说相当于零。因此第一条记录不会写入输出中。然后该条目从零更改为一。第二次读取相同的输入记录时,a[$0] 现在为 1。即“true”。该行将被打印。然而,在此之前,数组条目从1更新为2。依此类推。

11. 删除重复行

作为前一行的推论,我们可能想要删除重复的行:

awk '!a[$0]++' file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

唯一的区别是使用逻辑非运算符 (!) 反转表达式的真值。假的变成真,真的也变成假。逻辑对 ++ 后增量完全没有影响,其工作方式与以前完全相同。

C. 字段和记录分隔符魔法12. 更改字段分隔符awk '$1=$1' FS=, OFS=';' file CREDITS;EXPDATE;USER;GROUPS 99;01 jun 2018;sylvain;team:::admin 52;01 dec 2018;sonia;team 52;01 dec 2018;sonia;team 25;01 jan 2019;sonia;team 10;01 jan 2019;sylvain;team:::admin 8;12 jun 2018;öle;team:support 17;05 apr 2019;abhishek;guest

该程序将 FS 和 OFS 变量设置为使用逗号作为输入字段分隔符,使用分号作为输出字段分隔符。由于只要您不更改字段,AWK 就不会更改输出记录,因此使用 $1=$1 技巧来强制 AWK 破坏记录并使用输出字段分隔符重新组合它。

请记住这里的默认操作块是{ print }。所以你可以更明确地重写为:

awk '$1=$1 { print }' FS=, OFS=';' file CREDITS;EXPDATE;USER;GROUPS 99;01 jun 2018;sylvain;team:::admin 52;01 dec 2018;sonia;team 52;01 dec 2018;sonia;team 25;01 jan 2019;sonia;team 10;01 jan 2019;sylvain;team:::admin 8;12 jun 2018;öle;team:support 17;05 apr 2019;abhishek;guest

您可能已经注意到这两个示例也删除了空行。为什么?好吧,记住 AWK 转换规则:空字符串是“false”。 ” 所有其他字符串都是“true”。 ” 表达式 $1=$1 是一种改变 $1 的矫揉造作。然而,这也是一种表达。它的计算结果为 $1 的值——对于空字符串来说是“false”。如果您确实想要所有行,您可能需要编写类似的内容:

awk '($1=$1) || 1 { print }' FS=, OFS=';' file CREDITS;EXPDATE;USER;GROUPS 99;01 jun 2018;sylvain;team:::admin 52;01 dec 2018;sonia;team 52;01 dec 2018;sonia;team 25;01 jan 2019;sonia;team 10;01 jan 2019;sylvain;team:::admin 8;12 jun 2018;öle;team:support 17;05 apr 2019;abhishek;guest

您还记得 && 运算符吗?这是逻辑“与”。 || 是逻辑或。由于运算符优先级规则,括号在这里是必需的。如果没有它们,该模式将被错误地解释为 $1=($1 || 1)。我让你作为一个练习来测试结果会有什么不同。

最后,如果您不太热衷于算术,我敢打赌您会更喜欢更简单的解决方案:

awk '{ $1=$1; print }' FS=, OFS=';' file CREDITS;EXPDATE;USER;GROUPS 99;01 jun 2018;sylvain;team:::admin 52;01 dec 2018;sonia;team 52;01 dec 2018;sonia;team 25;01 jan 2019;sonia;team 10;01 jan 2019;sylvain;team:::admin 8;12 jun 2018;öle;team:support 17;05 apr 2019;abhishek;guest13. 删除多个空格awk '$1=$1' file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

这与前一个程序几乎相同。但是,我将字段分隔符保留为其默认值。因此,使用多个空格作为输入字段分隔符,但仅使用一个空格作为输出字段分隔符。这具有将多个空白合并为一个空间的良好副作用。

14. 使用 AWK 连接行

我们已经使用了 OFS,输出字段分隔符。正如您可能已经猜到的,它有对应的 ORS 来指定输出记录分隔符:

awk '{ print $3 }' FS=, ORS=' ' file; echo USER sylvain sonia sonia sonia sylvain öle abhishek

在这里,我在每个记录后面使用了一个空格而不是换行符。这一行在某些用例中已经足够了,但它仍然有一些缺点。

最明显的是,它不会丢弃仅包含空格的行(öle 后面的额外空格来自于此)。因此,我最终可能会使用普通的正则表达式:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo USER sylvain sonia sonia sonia sylvain öle abhishek

现在好多了,但仍然存在一个可能的问题。如果我们将分隔符更改为可见的内容,效果会更明显:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+

行尾有一个额外的分隔符 - 因为字段分隔符写在每条记录之后。包括最后一张。

为了解决这个问题,我将重写程序,从第二个输出记录开始,在记录之前显示自定义分隔符。

awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek

由于我自己负责添加分隔符,因此我还将标准 AWK 输出记录分隔符设置为空字符串。但是,当您开始处理分隔符或格式时,您可能应该考虑使用 printf 函数而不是 print 语句。正如我们现在将看到的那样。

D. 字段格式

我已经提到过 AWK 和 C 编程语言之间的关系。除此之外,AWK 从 C 语言标准库继承了强大的 printf 函数,可以很好地控制发送到输出的文本格式。

printf 函数采用格式作为第一个参数,其中包含将逐字输出的纯文本和用于格式化输出的不同部分的通配符。通配符由 % 字符标识。最常见的是 %s (用于字符串格式化)、%d (用于整数格式化)和 %f (用于浮点数格式化) )。由于这可能相当抽象,让我们看一个例子:

awk '+$1 { printf("%s ", $3) }' FS=, file; echo sylvain sonia sonia sonia sylvain öle abhishek

您可能会注意到,与 print 语句相反,printf 函数不使用 OFS 和 ORS价值观。因此,如果您想要一些分隔符,则必须像我一样通过在格式字符串末尾添加空格字符来明确提及它。这是完全控制输出所付出的代价。

虽然根本不是格式说明符,但这是引入 \n 表示法的绝佳机会,该表示法可在任何 AWK 字符串中用于表示换行符。

awk '+$1 { printf("%s\n", $3) }' FS=, file sylvain sonia sonia sonia sylvain öle abhishek15. 生成表格结果

AWK 强制执行基于分隔符的记录/字段数据格式。但是,使用 printf 函数,您还可以生成固定宽度的表格输出。因为 printf 语句中的每个格式说明符都可以接受可选的宽度参数:

awk '+$1 { printf("%10s | %4d\n", $3, $1) }' FS=, file sylvain | 99 sonia | 52 sonia | 52 sonia | 25 sylvain | 10 öle | 8 abhishek | 17

正如您所看到的,通过指定每个字段的宽度,AWK 将它们用空格填充到左侧。对于文本,通常最好在右侧填充,这可以使用负宽度数来实现。另外,对于整数,我们可能希望用零而不是空格来填充字段。这可以通过在字段宽度前使用显式 0 来获得:

awk '+$1 { printf("%-10s | %04d\n", $3, $1) }' FS=, file sylvain | 0099 sonia | 0052 sonia | 0052 sonia | 0025 sylvain | 0010 öle | 0008 abhishek | 001716. 处理浮点数

%f 格式不值得太多解释……

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file AVG=37.571429

…除了也许你几乎总是想显式设置显示结果的字段宽度和精度:

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file AVG= 37.6

这里,字段宽度为6,这意味着该字段将占据6个字符的空间(包括点,最终像通常一样在左侧填充空格)。 .1 精度意味着我们要显示点后 1 位小数的数字。我让您猜测 %06.1 会显示什么。

E. 在 AWK 中使用字符串函数

除了 printf 函数之外,AWK 还包含其他一些不错的字符串操作函数。在该领域中,像 Gawk 这样的现代实现具有更丰富的内部功能,但代价是可移植性较低。就我自己而言,我将在这里仅使用一些 POSIX 定义的函数,这些函数在任何地方都应该工作相同。

17. 将文本转换为大写

我经常使用它,因为它可以很好地处理国际化问题:

awk '$3 { print toupper($0); }' file 99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN 52,01 DEC 2018,SONIA,TEAM 52,01 DEC 2018,SONIA,TEAM 25,01 JAN 2019,SONIA,TEAM 10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN 8,12 JUN 2018,ÖLE,TEAM:SUPPORT 17,05 APR 2019,ABHISHEK,GUEST

事实上,这可能是从 shell 将文本转换为大写的最佳且最便携的解决方案。

18. 改变字符串的一部分

使用substr命令,您可以按给定长度分割字符串。这里我用它来仅将第三个字段的第一个字符大写:

awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,Sylvain,team:::admin 52,01 dec 2018,Sonia,team 52,01 dec 2018,Sonia,team 25,01 jan 2019,Sonia,team 10,01 jan 2019,Sylvain,team:::admin 8,12 jun 2018,Öle,team:support 17,05 apr 2019,Abhishek,guest

substr 函数采用初始字符串、要提取的第一个字符的(从 1 开始的)索引以及要提取的字符数。如果缺少最后一个参数,substr 会采用字符串的所有剩余字符。

因此,substr($3,1,1) 将计算为 $3 的第一个字符,substr($3,2) 将计算为剩余的字符那些。

19. 在子字段中拆分字段

AWK 记录字段数据模型非常好。但是,有时您希望根据某些内部分隔符将字段本身拆分为多个部分:

awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file 99,sylvain,jun,2018 52,sonia,dec,2018 52,sonia,dec,2018 25,sonia,jan,2019 10,sylvain,jan,2019 8,öle,jun,2018 17,abhishek,apr,2019

有点令人惊讶的是,即使我的某些字段被多个空格分隔,这仍然有效。主要是由于历史原因,当分隔符是单个空格时,split 会认为“元素由连续的空格分隔。 ”而且不仅仅是一个。 FS 特殊变量遵循相同的约定。

但一般情况下,一个字符串匹配一个字符。因此,如果您需要更复杂的东西,您必须记住字段分隔符是扩展的正则表达式。

作为示例,让我们看看如何处理使用冒号作为分隔符的多值字段组字段:

awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file sylvain team sonia team sonia team sonia team sylvain team öle team support abhishek guest

虽然我希望每个用户最多显示两个组,但它只为大多数用户显示一个组。该问题是由多次出现分隔符引起的。所以,解决方案是:

awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file sylvain team admin sonia team sonia team sonia team sylvain team admin öle team support abhishek guest

斜杠而不是引号表示文字是正则表达式而不是纯字符串,加号表示该表达式将匹配前一个字符的一次或多次出现。因此,在这种情况下,每个分隔符都由一个或几个连续的冒号(最长的序列)组成。

20. 使用AWK命令搜索和替换

说到正则表达式,有时您希望像 sed s///g 命令一样执行替换,但仅限于一个字段。在这种情况下,您需要使用 gsub 命令:

awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file 99 01-jun-2018 sylvain team:::admin 52 01-dec-2018 sonia team 52 01-dec-2018 sonia team 25 01-jan-2019 sonia team 10 01-jan-2019 sylvain team:::admin 8 12-jun-2018 öle team:support 17 05-apr-2019 abhishek guest

gsub 函数采用正则表达式进行搜索、替换字符串以及包含要就地修改的文本的变量。如果后面缺失,则假定为 $0。

F. 在 AWK 中使用外部命令

AWK 的另一个强大功能是您可以轻松调用外部命令来处理数据。基本上有两种方法可以做到这一点:使用 system 指令调用程序并让它在 AWK 输出流中混合其输出。或者使用管道,以便 AWK 可以捕获外部程序的输出,以便更好地控制结果。

这些本身可能是一个很大的话题,但这里有一些简单的例子来向您展示这些功能背后的力量。

21. 在文件顶部添加日期awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file UPDATED: Thu Feb 15 00:31:03 CET 2018 CREDITS,EXPDATE,USER,GROUPS 99,01 jun 2018,sylvain,team:::admin 52,01 dec 2018,sonia,team 52,01 dec 2018,sonia,team 25,01 jan 2019,sonia,team 10,01 jan 2019,sylvain,team:::admin 8,12 jun 2018,öle,team:support 17,05 apr 2019,abhishek,guest

在该 AWK 程序中,我首先显示已更新的工作。然后程序调用外部日期命令,该命令将在 AWK 在该阶段生成的文本之后立即在输出中发送其结果。AWK 程序的其余部分只是删除最终出现在文件中的更新语句并打印所有内容其他行(使用规则 1)。

请注意 next 语句。它用于中止当前记录的处理。这是忽略输入文件中某些记录的标准方法。

22. 外部修改字段

对于更复杂的情况,您可能需要考虑 | AWK 的 getline VARIABLE 习惯用法:

awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file 99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725 52,01 dec 2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3 52,01 dec 2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652 25,01 jan 2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4 10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2 8,12 jun 2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243 17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f

这将运行存储在 CMD 变量中的命令,读取该命令输出的第一行,并将其存储到变量 $5 中。

请特别注意 close 语句,它在这里至关重要,因为我们希望 AWK 在每次执行 CMD | 时创建外部命令的新实例。 getline 语句。如果没有 close 语句,AWK 将尝试从同一命令实例读取多行输出。

23.调用动态生成的命令

AWK 中的命令只是普通字符串,没有任何特殊内容。触发外部程序执行的是管道运算符。因此,如果需要,您可以使用 AWK 字符串操作函数和运算符动态构造任意复杂命令。

awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"' FS=, file 99 2018-06-01 sylvain team:::admin 52 2018-12-01 sonia team 52 2018-12-01 sonia team 25 2019-01-01 sonia team 10 2019-01-01 sylvain team:::admin 8 2018-06-12 öle team:support 17 2019-04-05 abhishek guest

我们已经认识了printf函数。 sprintf 非常相似,但会返回构建的字符串,而不是将其发送到输出。

24. 连接数据

为了向您展示关闭语句的目的,我让您尝试最后一个示例:

awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file 99 01 jun 2018 sylvain team:::admin 1e2a4f52 52 01 dec 2018 sonia team c23d4b65 52 01 dec 2018 sonia team 347489e5 25 01 jan 2019 sonia team ba985e55 10 01 jan 2019 sylvain team:::admin 81e9a01c 8 12 jun 2018 öle team:support 4535ba30 17 05 apr 2019 abhishek guest 80a60ec8

与上面使用 uuid 命令的示例相反,这里只有一个 od 实例在启动时启动AWK 程序正在运行,并且在处理每条记录时,我们会再读取该进程的输出的一行相同。

结论

AWK 的快速浏览当然不能取代该工具的完整课程或教程。然而,对于那些不熟悉它的人,我希望它能给您足够的想法,以便您可以立即将 AWK 添加到您的工具箱中。

另一方面,如果您已经是 AWK 爱好者,您可能会在这里找到一些技巧,您可以使用这些技巧来提高效率或只是为了给您的朋友留下深刻印象。

然而,我并不假装已经详尽无遗。因此,在任何情况下,请不要犹豫,使用下面的评论部分分享您最喜欢的 AWK 俏皮话或任何其他 AWK 技巧!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有