AWK 通过例子来介绍
AWK 是字符串操作语言,主要用于 UNIX 系统。AWK 背后的想法是创建一种在处理文件时使用的通用语言,这种语言并不太复杂,无法理解。
AWK 还有其他一些变体,但主要概念是相同的,只是附加功能。这些其他变体是 NAWK 和 GAWK。GAWK 包含两者的所有功能,如果你愿意,NAWK 比 AWK 高出一步。
想到 AWK 最简单的方法是考虑它有两个主要部分。模式和行动。
可能是 AWK 最基本的例子:(参见:Hello World)
BEGIN {print "START"}
{print }
END {print "STOP" }
这里,关键字 BEGIN
和 END
是模式,而动作在{}内。这个例子没用,但实际上只需要做一些小改动就可以使它成为一个有用的函数。
BEGIN {print "File\tAuthor"}
{print $8, "\t", $3}
END {print " - DONE - "}
这里,\t
表示 Tab 字符,用于平均输出行边界。 $ 8 和$ 3 类似于 Shell Scripts
中的使用,但它不使用第 3 和第 8 个参数,而是使用输入行的第 3 和第 8 列。
因此,此示例将打印:文件作者位于顶行,而第二行则处理文件路径。 $ 8 是文件的名称,$ 3 是所有者(当查看目录路径时,这将更加清晰)。最后,底线将打印,如你所料 - 完成 -
以上示例的信用转到 http://www.grymoire.com/Unix/Awk.html
参考文件
来自 Greg Goebel 的 coins.txt
:
gold 1 1986 USA American Eagle
gold 1 1908 Austria-Hungary Franz Josef 100 Korona
silver 10 1981 USA ingot
gold 1 1984 Switzerland ingot
gold 1 1979 RSA Krugerrand
gold 0.5 1981 RSA Krugerrand
gold 0.1 1986 PRC Panda
silver 1 1986 USA Liberty dollar
gold 0.25 1986 USA Liberty 5-dollar piece
silver 0.5 1986 USA Liberty 50-cent piece
silver 1 1987 USA Constitution dollar
gold 0.25 1987 USA Constitution 5-dollar piece
gold 1 1988 Canada Maple Leaf
最小的理论
一般 awk 单行:
awk <awk program> <file>
要么:
<shell-command> | awk <awk program>
<shell-command>
和 <file>
被称为 awk 输入。
<awk program>
是此模板后面的代码(单个,不是双引号):
'BEGIN {<init actions>};
<cond1> {<program actions>};
<cond2> {<program actions>};
...
END {<final actions>}'
哪里:
<condX>
条件通常是正则表达式/re/
,与 awk 输入行匹配;<* actions>
是语句序列,类似于 shell 命令,配有类似 C 的结构。
``按照以下规则处理:
BEGIN ...
和END ...
是可选的,在处理 awk 输入行之前或之后执行。- 对于 awk 输入中的每一行,如果条件
<condN>
为 meat,则执行相关的<program actions>
块。 {<program actions>}
默认为{print $0}
。
条件可以与标准逻辑运算符组合:
/gold/ || /USA/ && !/1986/
&&
优先于||
;
Theprint
声明。print item1 item2
语句在 STDOUT 上打印项目。
项目可以是变量(X
,$0
),字符串(hello
)或数字。
item1, item2
与 OFS
变量的值进行整理;
item1 item2
刚刚好 ! 使用 item1 " " item2
作为空格或 printf 以获得更多功能。
变量不需要 $
,即:print myVar;
以下特殊变量内置于 awk 中:
FS
:作为字段分隔符来分割字段中的 awk 输入行。我可以成为一个单一的角色,FS="c"
; 一个空字符串,FS=""
(然后每个单独的字符变成一个单独的字段); 一个没有斜线的正则表达式,FS="re"
;FS=" "
代表空格和制表符的运行,是默认值。NF
:要读取的字段数;$1
,$2
,…:第 1 场,第 2 场。等当前输入行,$0
:当前输入线;NR
:当前放线号。OFS
:打印时用于整理字段的字符串。ORS
:输出记录分隔符,默认为换行符。RS
:输入行(记录)分隔符。默认为换行符。设为FS
。IGNORECASE
:正则表达时影响 FS 和 RS;
例子
通过 regexp gold
过滤行并计算它们:
# awk 'BEGIN {print "Coins"} /gold/{i++; print $0} END {print i " lines out of " NR}' coins.txt
Coins
gold 1 1986 USA American Eagle
gold 1 1908 Austria-Hungary Franz Josef 100 Korona
gold 1 1984 Switzerland ingot
gold 1 1979 RSA Krugerrand
gold 0.5 1981 RSA Krugerrand
gold 0.1 1986 PRC Panda
gold 0.25 1986 USA Liberty 5-dollar piece
gold 0.25 1987 USA Constitution 5-dollar piece
gold 1 1988 Canada Maple Leaf
9 lines out of 13
基于内部 awk 变量 NR
的默认 print $0
动作和条件:
# awk 'BEGIN {print "First 3 coins"} NR<4' coins.txt
First 3 coins
gold 1 1986 USA American Eagle
gold 1 1908 Austria-Hungary Franz Josef 100 Korona
silver 10 1981 USA ingot
使用 C 风格的 printf
格式化:
# awk '{printf ("%s \t %3.2f\n", $1, $2)}' coins.txt
gold 1.00
gold 1.00
silver 10.00
gold 1.00
gold 1.00
gold 0.50
gold 0.10
silver 1.00
gold 0.25
silver 0.50
silver 1.00
gold 0.25
gold 1.00
条件例子
awk 'NR % 6' # prints all lines except those divisible by 6
awk 'NR > 5' # prints from line 6 onwards (like tail -n +6, or sed '1,5d')
awk '$2 == "foo"' # prints lines where the second field is "foo"
awk '$2 ~ /re/' # prints lines where the 2nd field mateches the regex /re/
awk 'NF >= 6' # prints lines with 6 or more fields
awk '/foo/ && !/bar/' # prints lines that match /foo/ but not /bar/
awk '/foo/ || /bar/' # prints lines that match /foo/ or /bar/ (like grep -e 'foo' -e 'bar')
awk '/foo/,/bar/' # prints from line matching /foo/ to line matching /bar/, inclusive
awk 'NF' # prints only nonempty lines (or: removes empty lines, where NF==0)
awk 'NF--' # removes last field and prints the line
通过添加动作 {...}
,可以打印特定字段,而不是整行,例如:
awk '$2 ~ /re/{print $3 " " $4}'
打印第二个字段匹配正则表达式/ re /的第三和第四个字段。
一些字符串函数
substr()
功能:
# awk '{print substr($3,3) " " substr($4,1,3)}'
86 USA
08 Aus
81 USA
84 Swi
79 RSA
81 RSA
86 PRC
86 USA
86 USA
86 USA
87 USA
87 USA
88 Can
match(s, r [, arr])
返回正在发生正则表达式 r
的 s
中的位置,并设置 RSTART
和 RLENGTH
的值。如果提供了参数 arr
,则返回数组 arr
,其中元素被设置为匹配的带括号的子表达式。arr
的第 0 个元素匹配设置为整个正则表达式匹配。表达式 arr[n, "start"]
和 arr[n, "length"]
也提供每个匹配子字符串的起始位置和长度。
更多字符串函数:
sub(/regexp/, "newstring"[, target])
gsub(/regexp/, "newstring"[, target])
toupper("string")
tolower("string")
声明
一个简单的陈述通常是以下任何一种:
variable = expression
print [ expression-list ]
printf format [ , expression-list ]
next # skip remaining patterns on this input line
exit # skip the rest of the input
如果 stat1
和 stat2
是陈述,以下也是陈述:
{stat}
{stat1; stat2}
{stat1
stat2}
if ( conditional ) statement [ else statement ]
以下标准 C-like 是构造语句:
if ( conditional ) statement [ else statement ]
while ( conditional ) statement
for ( expression ; conditional ; expression ) statement
break # usual C meaning
continue # usual C meaning
用于打印可变长度描述元素的 C 样式循环,从字段 4 开始:
# awk '{out=""; for(i=4;i<=NF;i++){out=out" "$i}; print out}' coins.txt
USA American Eagle
Austria-Hungary Franz Josef 100 Korona
USA ingot
Switzerland ingot
RSA Krugerrand
RSA Krugerrand
PRC Panda
USA Liberty dollar
USA Liberty 5-dollar piece
USA Liberty 50-cent piece
USA Constitution dollar
USA Constitution 5-dollar piece
Canada Maple Leaf
请注意,i
初始化为 0。
如果条件和计算应用于通用字段:
# awk '/gold/ {if($3<1980) print $0 "$" 425*$2}' coins.txt
gold 1 1908 Austria-Hungary Franz Josef 100 Korona $425
gold 1 1979 RSA Krugerrand $425
AWK 可执行脚本
#!/usr/bin/gawk -f
# This is a comment
(pattern) {action}
...
传递 shell 变量
# var="hello"
# awk -v x="$var" 'BEGIN {print x}'
hello