首页 存档 技术 查看内容

Linux Awk用法总结

2018-3-30 13:00 |来自: 互联网 374 0

摘要: 来自:Xiaoh's Blog 作者:pmars 链接:http://xiaoh.me/2016/03/23/awk-more/(点击尾部阅读原文前往) 目录 Awk是什么 命令行语法 脚本(Script)组成 模式(Pattern) 正则表达式(Regular Expression) 表达 ...

来自:Xiaoh's Blog

作者:pmars

链接:http://xiaoh.me/2016/03/23/awk-more/(点击尾部阅读原文前往)


目录

  1. Awk是什么

  2. 命令行语法

  3. 脚本(Script)组成

  4. 模式(Pattern)

  5. 正则表达式(Regular Expression)

  6. 表达式(Expressions)

  7. 数组

  8. 内置变量

    1. 删除ARGV元素

    2. 增加ARGV元素

    3. ARGV与ARGC

    4. CONVFMT与OFMT

    5. ENVIRON

    6. RLENGTH与RSTART

  9. 运算符

  10. 语句(Statement)

  11. 数学函数

  12. 字符串函数

    1. sub

    2. gsub

    3. index

    4. length

    5. match

    6. split

    7. sprintf

    8. substr

    9. tolower

    10. toupper

  13. I/O处理函数

    1. getline

    2. close

    3. system


作为另一篇关于Awk的文章的姐妹篇,这篇文章也是简述了Awk的使用方法。更多的内容实则是从以前的博客摘抄过来的。记载在这里,方便学习。

Awk是什么

Awk、sed与grep,俗称Linux下的三剑客,它们之前有很多相似点,但是同样也各有各的特色,相似的地方是它们都可以匹配文本,其中sed和awk还可以用于文本编辑,而grep则不具备这个功用。sed是一种非交互式且面向字符流的编辑器(a “non-interactive” stream-oriented editor),而awk则是一门模式匹配的编程语言,因为它的主要功能是用于匹配文本并处理,同时它有一些编程语言才有的语法,例如函数、分支循环语句、变量等等,当然比起我们常见的编程语言,Awk相对比较简单。

使用Awk,我们可以做以下事情:

  • 将文本文件视为由字段和记录组成的文本数据库;

  • 在操作文本数据库的过程中能够使用变量;

  • 能够使用数**算和字符串操作;

  • 能够使用常见的编程结构,例如条件分支与循环;

  • 能够格式化输出;

  • 能够自定义函数;

  • 能够在awk脚本中执行UNIX命令;

  • 能够处理UNIX命令的输出结果;

装备以上功能,awk能够做得事情非常多。但千里之行,始于足下,我们首先从最基本的命令行语法开始,一步一步得走入awk的编程世界。


命令行语法

同sed一样,awk的命令行语法也有两种形式:

awk [-F ERE] [-v assignment] ... program [argument ...]
awk [-F ERE] -f progfile ... [-v assignment] ...[argument ...]

这里的program类似sed中的script,因为我们一直强调awk是一门编程语言,所以将awk的脚本视为一段代码。而awk的脚本同样可以写到一个文件中,并通过-f参数指定,这一点和sed是一样的。program一般多个pattern和action序列组成,当读入的记录匹配pattern时,才会执行相应的action命令。这里有一点要注意,在第一种形式中,除去命令行选项外,program参数一定要位于第一个位置。

Awk的输入被解析成多个记录(Record),默认情况下,记录的分隔符是\n,因此可以认为一行就是一个记录,记录的分隔符可以通过内置变量RS更改。当记录匹配某个pattern时,才会执行后续的action命令。

而每个记录由进一步地被分隔成多个字段(Field),默认情况下字段的分隔符是空白符,例如空格、制表符等等,也可以通过-F ERE选项或者内置变量FS更改。在awk中,可以通过$1,$2…来访问对应位置的字段,同时$0存放整个记录,这一点有点类似shell下的命令行位置参数。关于这些内容,我们会在下面详细介绍,这里你只要知道有这些东西就好。

标准的awk命令行参数主要由以下三个:

  • -F ERE:定义字段分隔符,该选项的值可以是扩展的正则表达式(ERE);

  • -f progfile:指定awk脚本,可以同时指定多个脚本,它们会按照在命令行中出现的顺序连接在一起;

  • -v assignment:定义awk变量,形式同awk中的变量赋值,即name=value,赋值发生在awk处理文本之前;

为了便于理解,这里举几个简单的例子。通过-F参数设置冒号:为分隔符,并打印各个字段:

echo "1:2:3" | awk -F: '{print $1 " and " $2 " and " $3}'1 and 2 and 3

在awk的脚本中访问通过-v选项设置的变量:

echo | awk -v a=1 'BEGIN {print a}'1

从上面可以看到,通过-v选项设置的变量在BEGIN的位置就可以访问了。BEGIN是一个特殊的pattern,它在awk处理输入之前就会执行,可以认为是一个初始化语句,与此对应的还有END。

好像还没介绍如何指定处理的文件,是不是最后的argument就是指定的文件?在看我这本书之前,我也是这样认为的,但是实际上arguemnt有两种形式,它们分别是输入文件(file)和变量赋值(assignment)。

awk可以同时指定多个输入文件,如果输入文件的文件名为’-‘,表示从标准输入读取内容。

变量赋值类似-v选项,它的形式为name=value。awk中的变量名同一般的编程语言无太多区别,但是不能同awk的保留关键字重名,可以查看awk的man手册查询哪些是保留关键字。而变量值只有两种形式:字符串和数值。变量赋值必须位于脚本参数的后面,与文件名参数无先后顺序的要求,但是位于不同位置的赋值它的执行时机是不同的。

我们用实际的例子来解释这个区别,假设有两个文件:a和b,它们的内容分别如下所示:

cat a
file a
cat b
file b

为了说明赋值操作发生的时机,我们在BEGIN,正常处理,END三个地方都打印变量的值。

第一种情况: 变量赋值位于所有文件名参数之前

awk 'BEGIN {print "BEGIN: " var} {print "PROCESS: " var} END {print "END: " var }' var=1 a
BEGIN: 
PROCESS: 1
END: 1

结果:赋值操作发生在正常处理之前,BEGIN动作之后。

第二种情况:变量赋值位于所有文件名之后:

awk 'BEGIN {print "BEGIN: " var} {print "PROCESS: " var} END {print "END: " var }' a var=1 
BEGIN: 
PROCESS: 
END: 1

结果:赋值操作发生在正常处理之后,END动作之前。

第三种情况:变量赋值位于文件名之间:

awk 'BEGIN {print "BEGIN: " var} {print "PROCESS: " var} END {print "END: " var }' a var=1 b
BEGIN: 
PROCESS: 
PROCESS: 1
END: 1

结果:赋值操作发生在处理前面的文件之后,并且位于处理后面的文件之前;

总结如下:
  • 如果变量赋值在第一个文件参数之前,在BEGIN动作之后执行,影响到正常处理和END动作;

  • 如果变量赋值在最后一个文件参数之后,在END动作之前执行,仅影响END动作;

  • 如果文件参数不存在,情况同1所述;

  • 如果变量赋值位于多个文件参数之间,在变量赋值前面的文件被处理后执行,影响到后续文件的处理和END动作;

所以变量赋值一定要考虑清楚用途,否则比较容易出错,不过一般情况下也不会用到变量赋值。

自然地大家会将变量赋值与-v assignment选项进行比较,赋值的形式是一致的,但是-v选项的执行时机比变量赋值要早:

echo 1 | awk -v var=a 'BEGIN {print "BEGIN: " var}'BEGIN: a

可见,-v选项的赋值操作在BEGIN动作之前就执行了。

变量赋值一定要小心不要与保留关键字重名,否则会报错:

echo 1 | awk -v BEGIN=1 'BEGIN {print "BEGIN: " BEGIN}'awk: fatal: cannot use gawk builtin `BEGIN' as variable name

记录(Record)与字段(Field)

对于数据库来说,一个数据库表是由多条记录组成的,每一行表示一条记录(Record)。每条记录由多列组成,每一列表示一个字段(Field)。Awk将一个文本文件视为一个文本数据库,因此它也有记录和字段的概念。默认情况下,记录的分隔符是回车,字段的分隔符是空白符,所以文本文件的每一行表示一个记录,而每一行中的内容被空白分隔成多个字段。利用字段和记录,awk就可以非常灵活地处理文件的内容。

可以通过-F选项来修改默认的字段分隔符,例如/etc/passwd的每一行都是由冒号分隔成多个字段的,所以这里就需要将分隔符设置成冒号:

awk -F: '{print $1}' /etc/passwd | head -3root
bin
daemon

这里通过$1引用第一人字段,类似地$2表示第二个字段,$3表示第三个字段…. $0则表示整个记录。内置变量NF记录着字段的个数,所以$NF表示最后一个字段:

awk -F: '{print $NF}' /etc/passwd | head -3/bin/bash
/bin/false/bin/false

当然,$(NF-1)表示倒数第二个。

内置变量FS也可以用于更改字段分隔符,它记录着当前的字段分隔符:

awk -F: '{print FS}' /etc/passwd | head -1:
awk -v FS=: '{print $1}' /etc/passwd | head -1root

记录的分隔符可以通过内置变量RS更改:

awk -v RS=: '{print $0}' /etc/passwd | head -1root

如果将RS设置成空,行为有就一点怪异了,它会将连续不为空行的所有行(一个段落)当作一个记录,而且强制回车为字段分隔符:

cat awk_man.txt 
The awk utility shall execute programs written in the awk programming language,
which is specialized for textual data manipulation. An awk program is a sequenceof patterns and corresponding actions. When input is read that matches a 
pattern, the action associated with that pattern is carried out.Input shall be interpreted as a sequence of records. By default, a record is a line, 
less its terminating
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部