基础

基础知识 属于 AWK

1 个练习

关于 基础知识

我们把这门_语言_称为AWK,把解释 AWK 程序的_可执行文件_称为**awk或gawk**。

模式与动作

一个 AWK 程序由模式-动作对组成

pattern1 { action1 }
pattern2 { action2 }
...

模式可以是用来匹配输入的正则表达式,也可以是任何结果为 true/false 的表达式。

动作是一条或多条 AWK 命令。外面的大括号是必需的。

如果模式的结果为 true,就会执行与之对应的动作。

记录与字段

AWK 把输入解析成一系列记录。每条记录又被拆分成零个或多个字段。

默认行为是:

  • 用换行符作为“记录分隔符”把输入拆分成记录,所以每一_行_就是一条记录。
  • 用空白字符作为“字段分隔符”把记录拆分成字段,所以每一个_词_就是一个字段。

模式与动作(续)

模式可以省略,这时动作会_针对每一条输入记录_执行。

动作也可以省略,这时默认的动作就是打印当前记录。

特殊模式

有两个常用的特殊模式。

  • BEGIN会在读取任何输入之前执行与之关联的动作。
  • END会在所有输入读取完毕之后执行与之关联的动作。

字段变量

可以用$1、$2、$3等来引用字段。

当前记录是$0。

Caution

说得明确一些,它们严格来说并不是“变量”。 $可以看作一个_运算符_,用来取得给定字段编号的值。 我们会在后面的概念里深入讨论这一点。

下面还有一些其他常用的内置变量。

控制输入解析的内置变量

  • RS是输入记录分隔符。 如前所述,它的默认值是换行符。
  • FS是输入字段分隔符。

这些变量通常在BEGIN动作块中设置。

传递信息的内置变量

这些变量由 AWK 在程序执行过程中自动设置。

  • NF保存当前记录中的字段数。
    • 要取最后一个字段的值,可以使用$NF。
  • NR保存当前的记录编号。
    • 当处理多个输入文件时,NR会保存到目前为止处理过的记录总数。
  • FNR保存当前输入文件中的当前记录编号。
    • 为了说明 NR 和 FNR 的区别,这里给出一个常见的 AWK 惯用法。
      NR == FNR {action}
      
      它的意思是“如果累计的记录编号等于当前文件的记录编号”。 只有_第一个输入文件_中的记录才可能满足这个条件。

真值性

AWK 使用的真值性概念与 C 相同:

  • 数字0为 false。
  • 其他任何数字都为 true。

由于 AWK 是一门文本处理语言,真值也扩展到了字符串。

  • 空字符串""为 false。
  • 任何非空字符串都为 true。
Note

AWK 使用的真值性概念与 C 相同

AWK 于 20 世纪 70 年代诞生于贝尔实验室,那里的环境也正是 C 诞生的地方。 C 对 AWK 的语法有很大影响。

Caution

有一个需要留意的奇怪之处

  • 数字0为 false。
  • 非空字符串"0"却为 true!

我们会在后面的概念里进一步讨论 AWK 的数据类型。

注释

注释以#字符开头,一直延伸到行尾。

如何向awk提供输入

awk可以从文件或标准输入中读取输入。下面这些方法都可以用。

awk '/regex/ {print $1}' file1 file2 ...

awk '/regex/ {print $1}' < file

some_command_here | awk '/regex/ {print $1}'

示例

在类 Unix 系统上,/etc/passwd保存着用户信息。每个用户占一行,字段之间用冒号分隔。

要列出所有用户名:

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

注意,{print $1}这个动作没有模式,所以每条记录都会执行它。

如果我们只想输出登录 shell 为 bash 的用户,可以这样做:

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

更多示例

下面是一些 awk 程序,它们能产生与其他常见 Unix 命令相同的效果。

  • 显示文件

    cat file.txt
    
    awk '1' file.txt
    
  • 在文件中搜索模式

    grep 'foo.*bar' file.txt
    
    awk '/foo.*bar/' file.txt
    
  • 只显示文件开头的几行

    head -n 20 file.txt
    
    awk '
        1
        NR == 20 {exit}
    ' file.txt
    
  • 替换文件中的文本

    sed 's/foo/bar/' file.txt
    
    awk '{sub(/foo/, "bar")};1' file.txt
    # or more readably
    awk '
        {
            sub(/foo/, "bar")
            print
        }
    ' file.txt
    
通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 基础知识