目录
55. FS –输入字段分隔符
awk
默认的字段分隔符是空格,如果你的输入文件中不是一个空格作为字段分隔符,
你已经知道可以在 awk
命令行上使用
-F
选项来指定它
:
awk –F ‘,’ ‘{print $2,$3}’ employee.txt
同样的事情,也可以使用
awk
内置变量
FS
来完成。
FS
只能在
BEGIN
区域中使用。
awk ‘BEGIN {FS=”,”} {print $2,$3}’ employee.txt
BEGIN
区域可以包含多个命令,下面的例子中,
BEGIN
区域包含一个
FS
和一个
print
命令
.BEGIN
区域的多个命令之间,要用分号分隔。
$awk 'BEGIN { FS=",";\
> print "---------------------------\nName\tTitle\n------------------------"}\
> {print $2,"\t",$3;}\
> END {print "-----------------------------------------"}' employee.txt
---------------------------
Name Title
------------------------
John Doe CEO
Jason Smith IT Manager
Raj Reddy Sysadmin
Anand Ram Developer
Jane Miller Sales Manager
-----------------------------------------
注意:默认的字段分隔符不仅仅是单个空格字符,它实际上是一个或多个空白字符。
下面的
employee-multiple-fs.txt
文件,每行记录都包含
3
个不同的字段分隔符
:
z
,
雇员
id
后面的分隔符是逗号
z
:
雇员姓名后面的分隔符是分号
z
%
雇员职位后面的分隔符是百分号
创建文件
:
$vi employee-multiple-fs.txt
101,John Doe:CEO%10000
102,Jason Smith:IT Manager%5000
103,Raj Reddy:Sysadmin%4500
104,Anand Ram:Developer%4500
105,Jane Miller:Sales Manager%3000
当遇到一个包含多个字段分隔符的文件时,不必担心,
FS
可以搞定。你可以使用正则表达
式来指定多个字段分隔符,如
FS = “[,:%]”
指定字段分隔符可以是逗号
,
或者分号
:
或者百
分号
%
。
因此,下面的例子将打印
employee-multiple-fs.txt
文件中雇员名称和职位
.
$awk 'BEGIN {FS="[,:%]"}{print $2,$3}' employee-multiple-fs.txt
John Doe CEO
Jason Smith IT Manager
Raj Reddy Sysadmin
Anand Ram Developer
Jane Miller Sales Manager
56. OFS – 输出字段分隔符
FS
是输入字段分隔符,
OFS
是输出字段分隔符。
OFS
会被打印在输出行的连续的字段之间。
默认情况下,
awk
在输出字段中间以空格分开。
请注意,我们没有指定
IFS
作为输入字段分隔符,我们从简地使用
FS
。
下面的例子打印雇员姓名和薪水,并以空格分开。当你使用单个
print
语句打印多个以逗号
分开
(
如下面的例子所示
)
的变量是,每个变量之间会以空格分开。
$awk -F ',' '{print $2,$3}' employee.txt
John Doe CEO
Jason Smith IT Manager
Raj Reddy Sysadmin
Anand Ram Developer
Jane Miller Sales Manager
如果你尝试认为地在输出字段之间加上冒号,会有如下输出。请注意在冒号前后均有一个多
余的空格,这是因为
awk
仍然以空格作为输出字段分隔符。
下面的
print
语句实际上会打印
3
个值
(
以逗号分割
)
——
$2,:
和
$4.
因为如你所知,当使用单个
print
语句打印多个变量时,输出内容会包含多余的空格。
$awk -F ',' '{print $2,":",$3}' employee.txt
John Doe : CEO
Jason Smith : IT Manager
Raj Reddy : Sysadmin
Anand Ram : Developer
Jane Miller : Sales Manager
正确的方法是使用
awk
内置变量
OFS(
输出字段分隔符
)
,如下面了示例。请注意这个例子中
分号前后没有多余的空格,因为
OFS
使用冒号取代了
awk
默认的分隔符。
下面的
print
语句打印两个变量
($2
和
$4)
,使用都会分隔,然而输出结果却是以分号分隔
(
而
不是空格
),
因为
OFS
被设置成了分号
.
$awk -F ',' 'BEGIN {OFS=":"} {print $2,$3}' employee.txt
John Doe:CEO
Jason Smith:IT Manager
Raj Reddy:Sysadmin
Anand Ram:Developer
Jane Miller:Sales Manager
同时请注意在
print
语句中使用和不使用逗号的细微差别
(
打印多个变量时
).
当在
print
语句中
指定了逗号,
awk
会使用
OFS
。如下面的例子所示,默认的
OFS
会被使用,所以你会看到输
出值之间的空格。
$awk 'BEGIN { print "test1","test2"}'
test1 test2
不使用逗号是,
awk
将不会使用
OFS
,其输出变量之间没有任何空格。
$awk 'BEGIN { print "test1" "test2"}'
test1test2
57. RS – 记录分隔符
假定有下面一个文件,雇员的
id
和名称都在单一的一行内
.
$vi employee-one-line.txt
101,John Doe:102,Jason Smith:103,Raj Reddy:104,Anand Ram:105,Jane, Miller
这个文件中,每条记录包含两个字段
(empid
和
name),
并且每条记录以分红分隔
(
取代了换行
符
).
每条记录中的单独的字段
(empid
和
name)
以逗号分隔。
Awk
默认的记录分隔符是换行符。如果要尝试只打印雇员姓名,下面的例子无法完成:
$awk -F, '{print $2}' employee-one-line.txt
John Doe:102
这个例子把
employee-one-line.txt
的内容作为单独一行,把逗号作为字段分隔符,所以,它
打印
”John Doe:102
作为第二个字段。
如果要把文件内容作为
5
行记录来处理
(
而不是单独的一行
)
,并且打印每条记录中雇员的姓
名,就必须把记录分隔符指定为分号,如下所示:
$awk -F, 'BEGIN { RS=":" } {print $2}' employee-one-line.txt
John Doe
Jason Smith
Raj Reddy
Anand Ram
Jane Miller
假设有下面的文件,记录之间用-分隔,独占一行。所有的字段都占单独的一行。
$vi employee-change-fs-ofs.txt
101
John Doe
CEO
-
102
Jason Smith
IT Manager
-
103
Raj Reddy
Sysadmin
-
104
Anand Ram
Developer
-
105
Jane Miller
Sales Manager
上面例子中,字段分隔符
FS
是换行符,记录分隔符
RS
是
”-“
和换行符。所以如果要打印雇员
名称和职位,需要:
$awk 'BEGIN{RS="-\n";FS="\n";OFS=":"}{print $2,$3}' employee-change-fs-ofs.txt
John Doe:CEO
Jason Smith:IT Manager
Raj Reddy:Sysadmin
Anand Ram:Developer
Jane Miller:Sales Manager
58. ORS – 输出记录分隔符
RS
是输入字段分隔符,
ORS
是输出字段分隔符。请注意,我们没有指定
IFS
作为输入字段分
隔符,我们从简地使用
FS
。
下面的例子在每个输出行后面追加
”---------“.awk
默认使用换行符
”\n”
作为
ORS
,这个例子中,
我们使用”\n---\”作为 ORS。
$ awk 'BEGIN {FS=",";ORS="\n---\n"} {print $2,$3}' employee.txt
John Doe CEO
---
Jason Smith IT Manager
---
Raj Reddy Sysadmin
---
Anand Ram Developer
---
Jane Miller Sales Manager
---
下面的例子从 employee.txt 获取输入,把每个字段打印成单独一行,每条记录用”---“分隔
$ awk 'BEGIN { FS=",";OFS="\n";ORS="\n---\n"}{print $1,$2,$3}' employee.txt
101
John Doe
CEO
---
102
Jason Smith
IT Manager
---
103
Raj Reddy
Sysadmin
---
104
Anand Ram
Developer
---
105
Jane Miller
Sales Manager
---
59. NR – 记录序号
NR
非常有用,在循环内部标识记录序号。用于
END
区域时,代表输入文件的总记录数。
尽管你会认为
NR
代表
”
记录的数量
(Number of Records)”
,但它跟确切的叫法是
”
记录的序号
(Number of the Record)”,
也就是当前记录在所有记录中的行号。
下面的例子演示了
NR
在
block
和
END
区域是怎么运行的:
$ awk 'BEGIN {FS=","} \
> {print "Emp Id of record number",NR,"is",$1;}\
> END {print "Total number of records:",NR}' employee.txt
Emp Id of record number 1 is 101
Emp Id of record number 2 is 102
Emp Id of record number 3 is 103
Emp Id of record number 4 is 104
Emp Id of record number 5 is 105
Total number of records: 5
60. FILENAME – 当前处理的文件名
当使用
awk
处理多个输入文件时,
FILENAME
就显得很有用,它代表
awk
当前正在处理的文
件。
$ awk '{ print FILENAME }' \
> employee.txt employee-multiple-fs.txt
employee.txt
employee.txt
employee.txt
employee.txt
employee.txt
employee-multiple-fs.txt
employee-multiple-fs.txt
employee-multiple-fs.txt
employee-multiple-fs.txt
employee-multiple-fs.txt
如果
awk
从标准输入获取内容,
FILENAME
的值将会是
”-“
,下面的例中,我们不ᨀ供任何输
入文件,所以你应该手动输入内容以代替标准输入。
下面的例子中,我们只输入一个人名
”John Doe”
作为第一条记录
,
然后
awk
打印出该人的姓氏。
这种情况下,必须按
Ctrl-C
才能停止标准输入。
$ awk '{print "Last name:",$2;\
> print "Filename:",FILENAME}'
John Deo
Last name: Deo
Filename: -
上面这个例子在使用管道向
awk
传递数据时,同样适用。如下所示,打印出来的
FILENAME
仍然是
”-“
$ echo "Johe Doe" | awk '{print "Last name:",$2;\
> print "Filename:",FILENAME}'
Last name: Doe
Filename: -
注意
:
在
BEGIN
区域内,
FILENAME
的值是空,因为
BEGIN
区域只针对
awk
本身,而不处理任
何文件。
61. FNR – 文件中的 NR
我们已经知道
NR
是
”
记录条数
”(
或者叫
”
记录的序号
”),
代表
awk
当前处理的记录的行号。
在给
awk
传递了两个输入文件时
NR
会是什么?
NR
会在多个文件中持续增加,当处理到第
二个文件时,
NR
不会被重置为
1
,而是在前一个文件的
NR
基础上继续增加。
下面的例子中,第一个文件有
5
条记录,第二个文件也有
5
条记录。如下所示,当
body
区
域的循环处理到第二个文件时,
NR
从
6
开始递增
(
而不是
1).
最后在
END
区域,
NR
返回两个
文件的总记录条数。
$ awk 'BEGIN {FS=","}\
> {print FILENAME ": record number",NR,"is",$1;} \
> END {print "Total number of records:",NR}' \
> employee.txt employee-multiple-fs.txt
employee.txt: record number 1 is 101
employee.txt: record number 2 is 102
employee.txt: record number 3 is 103
employee.txt: record number 4 is 104
employee.txt: record number 5 is 105
employee-multiple-fs.txt: record number 6 is 101
employee-multiple-fs.txt: record number 7 is 102
employee-multiple-fs.txt: record number 8 is 103
employee-multiple-fs.txt: record number 9 is 104
employee-multiple-fs.txt: record number 10 is 105
Total number of records: 10
下面例子同时打印
NR
和
FNR:
$ awk -f fnr.awk employee.txt employee-multiple-fs.txt
FILENAME=employee.txt NR=1 FNR=1
FILENAME=employee.txt NR=2 FNR=2
FILENAME=employee.txt NR=3 FNR=3
FILENAME=employee.txt NR=4 FNR=4
FILENAME=employee.txt NR=5 FNR=5
FILENAME=employee-multiple-fs.txt NR=6 FNR=1
FILENAME=employee-multiple-fs.txt NR=7 FNR=2
FILENAME=employee-multiple-fs.txt NR=8 FNR=3
FILENAME=employee-multiple-fs.txt NR=9 FNR=4
FILENAME=employee-multiple-fs.txt NR=10 FNR=5
END Block:NR=10 FNR=5
资料来源于《SedandAwk101Hacks》,大家有兴趣可以买一本,也可以关注我,我更新完它。
曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。
只为学习交流,不为获利,侵权联系立删。