awk man帮助文档翻译

mawk 是一种用于模式扫描和文本处理的解释器,它实现了 AWK 编程语言。AWK 语言对于数据文件的操作、文本检索和处理,以及算法的原型和实验都非常有用。mawk 是新的 AWK 实现,它遵循 POSIX 1003.2(草案 11.3)对 AWK 语言的定义,其中包含一些 AWK 书中未描述的特性,并提供了一些扩展功能。

AWK 程序由一系列模式 {动作} 对和用户函数定义组成。短程序通常在命令行中输入,通常用 ’ ’ 括起来以避免 shell 解释。更长的程序可以通过 -f 选项从文件中读取。数据输入从命令行上的文件列表或空列表时从标准输入读取。输入根据记录分隔符变量 RS 进行分割。初始情况下,RS = “\n”,记录与行同义。每个记录与每个模式进行比较,如果匹配,则执行 {动作} 的程序文本。

以下是 mawk 提供的选项:

  • -F value:将字段分隔符 FS 设置为指定的值。
  • -f file:从文件中读取程序文本,而不是从命令行中读取。允许多个 -f 选项。
  • -v var=value:将值分配给程序变量 var。
  • --:表示选项的明确结束。
  • -W dump:将程序的内部表示写成类似汇编的列表,并退出 0(在成功编译时)。
  • -W exec file:从文件中读取程序文本,这是最后一个选项。这是支持可执行脚本的系统上的有用替代 -f 的选项。
  • -W help:将使用消息打印到 stderr 并退出(与“-W usage”相同)。
  • -W interactive:将 stdout 设置为无缓冲写入,将 stdin 设置为行缓冲读取。stdin 中的记录始终是行,而不管 RS 的值如何。
  • -W posix_space:强制 mawk 不将 ‘\n’ 视为空格。
  • -W random=num:使用给定的参数调用 srand(并覆盖自动种子行为)。
  • -W sprintf=num:调整 mawk 内部 sprintf 缓冲区的大小为 num 字节。多次使用此选项表明应重新编译 mawk
  • -W usage:将使用消息打印到 stderr 并退出(与“-W help”相同)。
  • -W version:将 mawk 的版本和版权写入 stdout,并将编译限制写入 stderr,并退出 0。
  • mawk 允许将多个 -W 选项组合,用逗号分隔,例如 -Wsprint=2000,posix。这对于支持可执行脚本的“魔术数字”调用非常有用,其中仅支持一个参数,例如 -Winteractive,exec

AWK 语言

  1. 程序结构

    • AWK 程序由一系列模式 {动作} 对用户函数定义组成。

    • 模式

      可以是:

      • BEGIN
      • END
      • expression
      • expression , expression
    • 模式 {动作} 中的一个可以省略。如果省略了 {动作},则默认为 { print }。如果省略了模式,则隐式匹配。BEGINEND 模式需要一个动作。

    • 语句以换行符、分号或两者结尾。语句组(例如动作或循环体)通过 { … } 进行分组,类似于 C 语言。块中的最后一个语句不需要终止符。空行没有意义;空语句以分号终止。长语句可以使用反斜杠 **** 继续。语句可以在逗号、左大括号、&&||doelseifwhilefor 语句的右括号以及函数定义的右括号之后不使用反斜杠进行换行。注释以 # 开头,延伸到但不包括行尾。

    下面的语句控制块内的程序流程。

    • if ( expr ) statement
    • if ( expr ) statement else statement
    • while ( expr ) statement
    • do statement while ( expr )
    • for ( opt_expr ; opt_expr ; opt_expr ) statement
    • for ( var in array ) statement
    • continue
    • break

2. 数据类型、转换和比较

在 AWK 语言中,有两种基本数据类型:数值字符串。数值常量可以是整数(如 -2)、小数(如 1.08)或科学计数法表示(如 -1.1e4 或 .28E-3)。所有数字在内部都以浮点数表示,所有计算都使用浮点数算术进行。因此,例如,表达式 0.2e2 == 20 为真,而 true 表示为 1.0。

字符串常量用双引号括起来:

"This is a string with a newline at the end.\n"

字符串可以通过转义(\)换行来跨越多行。以下转义序列被识别:

  • \\:反斜杠
  • \":双引号
  • \a:警报(ASCII 7)
  • \b:退格(ASCII 8)
  • \t:制表符(ASCII 9)
  • \n:换行符(ASCII 10)
  • \v:垂直制表符(ASCII 11)
  • \f:换页符(ASCII 12)
  • \r:回车符(ASCII 13)
  • \ddd:1、2 或 3 个八进制数字(ASCII ddd)
  • \xhh:1 或 2 个十六进制数字(ASCII hh)

如果转义其他字符 \c,则会得到 \c,即 mawk 忽略了该转义。

实际上,有三种基本数据类型:数值和字符串,它们同时具有数值值和字符串值。用户定义的变量在首次引用时创建,并初始化为 null,即数值值为 0,字符串值为空字符串 “”。非平凡的数值和字符串类型的数据来自输入,通常存储在字段中。

表达式的类型由其上下文决定,如果需要,将自动进行类型转换。例如,要计算以下语句:

y = x + 2; z = x "hello"

变量 y 中存储的值将是数值类型。如果 x 不是数值,从 x 读取的值在加上 2 之前将被转换为数值,并存储在 y 中。变量 z 中存储的值将是字符串类型,如果需要,x 的值将被转换为字符串,并与 “hello” 连接。请注意,x 中存储的值和类型不会因为任何转换而改变。字符串表达式使用其最长的数值前缀进行数值转换,类似于 atof(3)。数值表达式通过将 expr 替换为 sprintf(CONVFMT, expr) 进行字符串转换,除非 expr 可以在主机机器上表示为精确整数,否则将转换为 sprintf("%d", expr)Sprintf() 是一个内置的 AWK 函数,它复制了 sprintf(3) 的功能,而 CONVFMT 是一个内置变量,用于从数值到字符串的内部转换,初始值为 "%.6g"。可以强制执行显式类型转换,例如,expr "" 是字符串,expr+0 是数值。

在评估 expr1 rel-op expr2 时,如果两个操作数都是数值或数值和字符串,则比较是数值的;如果两个操作数都是字符串,则比较是字符串的;如果一个操作数是字符串,则将非字符串操作数转换,比较是字符串的。结果是数值,为 1 或 0。

在布尔上下文中(例如,if (expr) statement),如果字符串表达式不是空字符串 “”,则为真;数值值仅在不为数值零时为真。

3 Regular expressions

在AWK语言中,记录、字段和字符串经常被用于匹配正则表达式。正则表达式被包含在斜杠中,例如:

expr ~ /r/

这是一个AWK表达式,如果expr“匹配”了r,也就是说expr的一个子串属于由r定义的字符串集合,那么它的值为1。如果没有匹配,表达式的值为0;用“不匹配”运算符!~替换~会反转其含义。作为模式-动作对,以下两种写法是等价的:

/r/ { action }
$0 ~ /r/ { action }

对于每个与r匹配的输入记录,都会执行action。实际上,/r/是一个AWK表达式,除了在匹配运算符的右侧或作为传递给期望正则表达式参数的内置函数的参数时,它与($0 ~ /r/)等效。

AWK使用扩展的正则表达式,就像grep(1)的-E选项一样。正则表达式的元字符,即在正则表达式中具有特殊含义的字符,包括:

  • \:匹配非元字符c
  • \c:匹配由字符串常量中使用的相同转义序列定义的字符,或者如果\c不是转义序列,则匹配字面字符c
  • .:匹配任何字符(包括换行符)。
  • ^:匹配字符串的开头。
  • $:匹配字符串的结尾。
  • [c1c2c3...]:匹配类c1c2c3...中的任何字符。字符区间在类[...]内用c1-c2表示。
  • [^c1c2c3...]:匹配不在类c1c2c3...中的任何字符。

正则表达式可以由其他正则表达式组合而成:

  • r1r2:匹配紧接在r1后面的r2(连接)。
  • r1 | r2:匹配r1r2(选择)。
  • r*:匹配r重复零次或更多次。
  • r+:匹配r重复一次或更多次。
  • r?:匹配r零次或一次。
  • (r):提供分组,匹配r

运算符的优先级递增顺序为:选择、连接和一元运算符(*+?)。

例如,以下正则表达式分别匹配AWK标识符和AWK数值常量:

  • /^[_a-zA-Z][_a-zA-Z0-9]*$/
  • /^[-+]?([0-9]+\.?|\.[0-9])[0-9]*([eE][-+]?[0-9]+)?$/

请注意,“.”必须转义为被识别为小数点,而在字符类内部,元字符不是特殊字符。

在AWK中,任何表达式都可以用作~!~运算符的右操作数,或者传递给期望正则表达式参数的内置函数。如果需要,它会被转换为字符串,然后解释为正则表达式。例如:

BEGIN { identifier = "[_a-zA-Z][_a-zA-Z0-9]*" }
$0 ~ "^" identifier

将打印所有以AWK标识符开头的行。

mawk识别空正则表达式//,它匹配空字符串,因此在每个字符的前、后和之间都与任何字符串匹配。例如:

echo abc | mawk '{ gsub(//, "X"); print
XaXbXcX

4、记录和字段

  • 记录逐一读取,并存储在字段变量 $0 中。

  • 记录被分割成字段,存储在 $1$2、…、$NF 中。

  • 内置变量 NF 设置为字段数。

  • 超过 $NF 的字段被设置为空字符串。

  • $0 的赋值会重新计算字段和 NF

  • NF 或字段的赋值会重构 $0,通过连接 $i,用 OFS 分隔。

  • 存储在字段中的数据是字符串,除非整个字段具有数值形式,此时类型为数值和字符串。例如:

    echo 24 24E |
    mawk '{ print($1>100, $1>"100", $2>100, $2>"100") }'
    0 1 1 1
    

    $0$2 是字符串,$1 是数值和字符串。第一个比较是数值,第二个是字符串,第三个和最后一个都是字符串(100 被转换为 “100”)。

5、表达式和运算符

  • 表达式语法类似于 C。
  • 主要表达式包括数值常量、字符串常量、变量、字段、数组和函数调用。
  • 变量不需要声明;它们在首次引用时存在并初始化为空。
  • 运算符包括赋值、条件、逻辑、关系、算术、一元等。
  • 表达式可以使用括号进行分组。

6、数组

  • Awk 提供一维数组。

  • 数组元素表示为 array[expr]

  • 以字符串为索引的数组称为关联数组。

  • 初始状态下,数组为空;元素在首次访问时创建。

  • 表达式 expr in array 评估为 1 如果 array[expr] 存在,否则为 0。

  • 有一种循环遍历数组索引的 for 语句形式:

    for (var in array) statement
    

    var 设置为数组的每个索引,并执行 statement。遍历顺序未定义。

  • 语句 delete array[expr] 使 array[expr] 不再存在。mawk 支持扩展,delete array 可删除数组的所有元素。

  • 多维数组使用内置变量 SUBSEP 进行合并。array[expr1,expr2] 等同于 array[expr1 SUBSEP expr2]。测试多维元素使用括号索引,例如:

    if ((i, j) in A) print A[i, j]
    

7、内置变量 下面的变量是内置的,并在程序执行之前初始化。

  • ARGC:命令行参数的数量。
  • ARGV:命令行参数的数组,索引从0到ARGC-1。
  • CONVFMT:用于将数字转换为字符串的内部格式,默认为"%.6g"。
  • ENVIRON:由环境变量索引的数组。环境字符串var=value存储为ENVIRON[var] = value。
  • FILENAME:当前输入文件的名称。
  • FNR:FILENAME中的当前记录号。
  • FS:将记录拆分为字段的正则表达式。
  • NF:当前记录中的字段数。
  • NR:总输入流中的当前记录号。
  • OFMT:用于打印数字的格式,初始值为"%.6g"。
  • OFS:输出时字段之间插入的分隔符,初始值为" "。
  • ORS:输出时终止每个记录的分隔符,初始值为"\n"。
  • RLENGTH:由最后一次调用内置函数match()设置的长度。
  • RS:输入记录分隔符,初始值为"\n"。
  • RSTART:由最后一次调用match()设置的索引。
  • SUBSEP:用于构建多个数组下标的分隔符,初始值为"\034"。12

8、内置函数 字符串函数:

  • gsub(r, s, t):全局替换,将变量t中的每个与正则表达式r匹配的部分替换为字符串s。返回替换的次数。如果省略t,则使用$0。替换字符串s中的&将被替换为t中的匹配子串。&和\分别表示替换字符串中的&和\。
  • index(s, t):如果t是s的子串,则返回t开始的位置,否则返回0。s的第一个字符在位置1。
  • length(s):返回字符串或数组s的长度。
  • match(s, r):返回字符串s中最长正则表达式r的第一个匹配的索引。如果没有匹配,则返回0。作为副作用,RSTART设置为返回值。如果匹配为空字符串,则RLENGTH设置为0;如果匹配在前面,则返回1;如果匹配在后面,则返回length(s)+1。
  • split(s, A, r):使用正则表达式r将字符串s拆分为字段,并将字段加载到数组A中。返回字段数。有关更详细的信息,请参见下面的第11节。如果省略r,则使用FS。
  • sprintf(format, expr-list):根据format从expr-list构造字符串。有关printf()的描述,请参见下面的描述。
  • sub(r, s, t):单一替换,与gsub()相同,但最多只进行一次替换。
  • substr(s, i, n):返回字符串s从索引i开始的长度为n的子串。如果省略n,则返回从i开始的s的后缀。

时间函数:

这些函数适用于支持相应C mktime和strftime函数的系统:

  • mktime(specification):将日期规范转换为与systime相同单位的时间戳。日期规范是包含日期组件的字符串,这些组件是十进制整数:
    • YYYY:年份,例如2012。
    • MM:从1开始的月份。
    • DD:从1开始的日期。
    • HH:小时(0-23)。
    • MM:分钟(0-59)。
    • SS:秒(0-59)。
    • DST:指示如何处理时区与夏令时:
      • 正数:夏令时有效。
      • 零(默认):夏令时无效。
      • 负数:mktime()应(使用时区信息和系统数据库)尝试确定指定时间是否处于夏令时。
  • strftime([format [, timestamp [, utc ]]]):使用格式(传递给C strftime函数)格式化给定的时间戳:
    • 如果缺少format参数,则使用"%c"。
    • 如果缺少timestamp参数,则使用systime的当前值。
    • 如果存在且非零的utc参数,则结果为UTC。否则使用本地时间。
  • systime():返回自纪元(1970-01-01 00:00:00 UTC,POSIX系统上)以来的当前时间,以秒为单位。

算术函数:

  • atan2(y, x):y/x的反正切,介于-pi和pi之间。
  • cos(x):余弦函数,x以弧度为单位。
  • exp(x):指数函数。
  • int(x):返回截断为零的x。
  • log(x):自然对数。
  • rand():返回0到1之间的随机数。
  • sin(x):正弦函数,x以弧度为单位。
  • sqrt(x):返回x的平方根。
  • srand(expr):使用时钟种子随机数生成器,如果省略expr,则返回先前种子的值。srand(expr)用于重复伪随机序列。

注意:mawk通常配置为在启动时从时钟种子随机数生成器,使得无需调用srand()。此功能可以通过条件编译来抑制,或者使用-Wrandom选项来覆盖。1

9、输入和输出 有两个输出语句,print和printf。

 print  将 $0  ORS 写入标准输出。

 print expr1, expr2, ..., exprn
        将 expr1 OFS expr2 OFS ... exprn ORS 写入标准输出。数字表达式将使用 OFMT 转换为字符串。

 printf format, expr-list
        复制 C 库函数 printf 到标准输出。完全识别 ANSI C 格式规范,包括转换 %c, %d, %e, %E, %f, %g, %G, %i, %o, %s, %u, %x, %X 和 %%,以及转换限定符 h 和 l。

print 或 printf 的参数列表可以选择性地用括号括起来。Print 使用 OFMT 或 "%d" 格式化数字。"%c" 带有数字参数时,打印相应的8位字符,带有字符串参数时,打印字符串的第一个字符。print 和 printf 的输出可以通过在 print 语句的末尾添加 > file, >> file 或 | command 重定向到文件或命令。重定向只打开一次文件或命令,后续的重定向将追加到已经打开的流中。按照惯例,mawk 将文件名

• "/dev/stderr" 与 stderr 关联,

• "/dev/stdout" 与 stdout 关联,

• "-" 和 "/dev/stdin" 与 stdin 关联。

与 stderr 的关联特别有用,因为它允许将 print 和 printf 重定向到 stderr。这些名称也可以传递给函数。

输入函数 getline 有以下变体。

 getline
        读入 $0,更新字段,NF,NR 和 FNR。

 getline < file
        从文件读入 $0,更新字段和 NF。

 getline var
        读取下一条记录到 var,更新 NR 和 FNR。

 getline var < file
        读取文件的下一条记录到 var。

 command | getline
        从命令管道一条记录到 $0 并更新字段和 NF。

 command | getline var
        从命令管道一条记录到 var。

Getline 在文件结束时返回 0,在错误时返回 -1,否则返回 1。

管道末端的命令由 /bin/sh 执行。

函数 close(expr) 关闭与 expr 关联的文件或管道。如果 expr 是一个打开的文件,Close 返回 0,如果 expr 是一个管道命令,返回退出状态,否则返回 -1。Close 用于重新读取文件或命令,确保输出管道的另一端已完成或节省文件资源。

函数 fflush(expr) 刷新与 expr 关联的输出文件或管道。如果 expr 是一个打开的输出流,Fflush 返回 0,否则返回 -1。没有参数的 Fflush 刷新 stdout。带有空参数 ("")

10 用户定义的函数 用户定义函数的语法是

    function name( args ) { statements }

函数体可以包含一个返回语句

    return opt_expr

返回语句不是必需的。函数调用可以嵌套或递归。函数通过值传递表达式,通过引用传递数组。额外的参数作为局部变量,并初始化为 null。例如,csplit(s,A) 将 s 的每个字符放入数组 A,并返回 s 的长度。

    function csplit(s, A,    n, i)
    {
      n = length(s)
      for( i = 1 ; i <= n ; i++ ) A[i] = substr(s, i, 1)
      return n
    }

在传递的参数和局部变量之间放置额外的空格是惯例。函数可以在定义之前被引用,但是函数名和参数的 ‘(’ 必须接触,以避免与连接混淆。

函数参数通常是标量值(数字或字符串)。如果对使用数组作为参数的函数有前向引用,函数的相应参数将被视为数组。

11 分割字符串、记录和文件 Awk 程序使用相同的算法将字符串分割成 split() 的数组,将记录分割成 FS 的字段。mawk 基本上使用相同的算法将文件分割成 RS 的记录。

Split(expr,A,sep) 的工作方式如下:

(1) 如果省略了 sep,它将被替换为 FS。Sep 可以是表达式或正则表达式。如果它是非字符串类型的表达式,它将被转换为字符串。

(2) 如果 sep = " "(一个单独的空格),那么 将从 expr 的前面和后面去除,sep 变成 。mawk 将 定义为正则表达式 /[ \t\n]+/。否则,sep 被视为正则表达式,除了对长度为 1 的字符串忽略元字符,例如,split(x, A, “”) 和 split(x, A, //) 是相同的。

(3) 如果 expr 不是字符串,它将被转换为字符串。如果 expr 然后是空字符串 “”,split() 返回 0 并将 A 设置为空。否则,sep 在 expr 中的所有非重叠、非空且最长的匹配,将 expr 分割成字段,这些字段被加载到 A 中。字段被放置在 A[1], A[2], …, A[n] 中,split() 返回 n,字段的数量是匹配的数量加一。看起来是数字的数据被放入 A 并被键入为数字和字符串。

分割记录到字段的工作方式相同,只是片段被加载到 $1, $2,…, $NF。如果 $0 为空,NF 设置为 0,所有 $i 设置为 “”。

mawk 使用相同的算法将文件分割成记录,但有一个细微的区别,即 RS 实际上是一个终止符而不是一个分隔符。(ORS 也确实是一个终止符)。

 例如,如果 FS = “:+” 并且 $0 = “a::b:”,那么 NF = 3 并且 $1 = “a”,$2 = “b” 并且 $3 = "",但是如果 “a::b:” 是输入文件的内容并且 RS = “:+”,那么有两个记录 “a” 和 “b”。

RS = " " 不是特殊的。

如果 FS = “”,那么 mawk 将记录分割成单个字符,类似地,split(s,A,“”) 将 s 的单个字符放入 A。

  1. 多行记录

由于mawk将RS(记录分隔符)解释为正则表达式,多行记录的处理变得很容易。设置RS = "\n\n+",可以使一个或多个空行分隔记录。如果FS(字段分隔符) = " "(默认值),那么根据的规则,单独的换行符会变成空格,并且单独的换行符会成为字段分隔符。

例如,如果:

  • 一个文件的内容是 "a b\nc\n\n",
  • RS = "\n\n+",
  • FS = " ",

那么就会有一个记录“a b\nc”,它包含三个字段:“a”,“b”和“c”。

  • 如果将FS更改为“\n”,则会有两个字段:“a b”和“c”;
  • 如果将FS更改为“”,则会有一个字段,它与记录相同。

如果你想让包含空格或制表符的行被视为空行,可以将RS设置为“\n([ \t]*\n)+”。为了与其他awk兼容,设置RS = ""的效果与从文件的前面和后面去除空行,然后确定记录(就好像RS = “\n\n+”一样)的效果相同。POSIX要求当RS = ""时,“\n”始终分隔记录,无论FS的值如何。mawk不支持此约定,因为将“\n”定义为使得它变得不必要。

大多数时候,当你为多行记录更改RS时,你也希望将ORS更改为“\n\n”,以便在输出时保留记录间距。

13 程序执行 本节描述了程序执行的顺序。首先,ARGC设置为传递给程序执行阶段的命令行参数的总数。ARGV[0]设置为AWK解释器的名称,ARGV1 … ARGV[ARGC-1]保存除选项和程序源之外的其余命令行参数。例如:

mawk -f prog v=1 A t=hello B

其中 ARGC = 5,ARGV[0] = “mawk”,ARGV1 = “v=1”,ARGV2 = “A”,ARGV3 = “t=hello”,ARGV4 = “B”。

接下来,按顺序执行每个 BEGIN 块。如果程序完全由 BEGIN 块组成,则执行终止,否则打开输入流并继续执行。如果 ARGC 等于 1,则输入流设置为 stdin,否则检查命令行参数 ARGV1 … ARGV[ARGC-1] 是否为文件参数。

命令行参数分为三组:文件参数、赋值参数和空字符串 “”。赋值的形式为 var=string。当检查 ARGV[i] 是否为可能的文件参数时,如果它为空,则跳过;如果它是赋值参数,则进行 var 的赋值并跳到下一个参数;否则打开 ARGV[i] 作为输入。如果打开失败,执行终止,退出代码为 2。如果没有命令行参数是文件参数,则输入来自 stdin。在 BEGIN 动作中,Getline 打开输入。

一旦打开输入流,每个输入记录都与每个模式进行匹配,如果匹配,则执行相关的动作。表达式模式在布尔值为 true 时匹配(参见第 2 节)。BEGIN 模式在读取任何输入之前匹配,END 模式在读取所有输入之后匹配。范围模式 expr1,expr2 匹配 expr1 和 expr2 之间的每个记录,包括这两个模式的匹配。

当输入流到达文件末尾时,检查剩余的命令行参数是否为文件参数,如果是,则打开该文件,否则认为 END 模式已匹配,并执行所有 END 动作。

在模式 {action} 级别上,程序流程可以通过以下语句进行更改:

posted @ 2024-04-07 16:21  hackintosh  阅读(2)  评论(0编辑  收藏  举报