Linux 文件管理-文件内容-分析工具【awk】脚本处理文本和数据-Linux 文本操作三剑客
1. awk简介
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
1.1. awk的工作原理
```shell
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
```
* 第一步:执行`BEGIN{ commands }`语句块中的语句;
* 第二步:从文件或标准输入(stdin)读取一行,然后执行`pattern{ commands }`语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
* 第三步:当读至输入流末尾时,执行`END{ commands }`语句块。
**BEGIN语句块** 在awk开始从输入流中读取行 **之前** 被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
**END语句块** 在awk从输入流中读取完所有的行 **之后** 即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
**pattern语句块** 中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行`{ print }`,即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
**示例**
当使用不带参数的`print`时,它就打印当前行,当`print`的参数是以逗号进行分隔时,打印时则以空格作为定界符。在awk的print语句块中双引号是被当作拼接符使用,例如:
双引号拼接使用:
{ }类似一个循环体(Empty Patterns),会对文件中的每一行进行迭代,通常变量初始化语句(如:i=0)以及打印文件头部的语句放入BEGIN语句块中,将打印的结果等语句放在END语句块中。
2. awk命令格式和选项
2.1. awk的语法有两种形式
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
注意: 'script' 只能使用单引号!!!!!!!
2.2. 常用命令选项
指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
-v var=value or --asign var=value
-f scripfile or --file scriptfile
对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
-W compact or --compat, -W traditional or --traditional
在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
-W copyleft or --copyleft, -W copyright or --copyright
-W help or --help, -W usage or --usage
打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。
-W re-interval or --re-inerval
允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
-W source program-text or --source program-text
更多选项可查看官网: http://www.gnu.org/software/gawk/manual/html_node/Options.html#Options
3. 模式和操作
如$ awk '/root/' test,或$ awk '$3 < 100' test。
- 如果没有模式,则action应用到全部记录,
- 如果没有action,输出匹配全部记录,
- 默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
3.1. 模式(pattern )
模式名 | 解释 | 版本要求 | 范例 | |
/正则表达式/ Regexp Patterns |
使用通配符的扩展集。 | |||
关系表达式 Expression Patterns |
可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行 | |||
模式匹配表达式 | 用运算符~(匹配)和~!(不匹配) | |||
BEGIN/END Patterns | Begin | 让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。 | ||
end |
让用户在最后一条输入记录被读取之后发生的动作。 |
|||
BEGINFILE/ENDFILE | gawk | |||
Empty Patterns | The empty pattern, which matches every record. |
|
3.2. 操作(action)
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。主要有四部份:
变量或数组赋值
输出命令
内置函数
控制流命令
4. awk的环境变量
Table 1. awk的环境变量
变量 | 长参数 | 描述 |
---|---|---|
$n | 当前记录的第n个字段,字段间由FS分隔。 | |
$0 | 完整的输入记录。 | |
ARGC | 命令行参数的数目。 | |
ARGIND | 命令行中当前文件的位置(从0开始算)。 | |
ARGV | 包含命令行参数的数组。 | |
CONVFMT | 数字转换格式(默认值为%.6g) | |
ENVIRON | 环境变量关联数组。 | |
ERRNO | 最后一个系统错误的描述。 | |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)。 | |
FILENAME | 当前文件名。 | |
FNR | 同NR,但相对于当前文件。 | |
F|fs | --field-separator | 字段分隔符(默认是任何空格)。 |
IGNORECASE | 如果为真,则进行忽略大小写的匹配。{IGNORECASE=1; } | |
NF | 一行中的最后一个字段 | |
NR | 当前记录数。 | |
OFMT | 数字的输出格式(默认值是%.6g)。 | |
OFS | 输出字段分隔符(默认值是一个空格)。 | |
ORS | 输出记录分隔符(默认值是一个换行符)。 | |
RLENGTH | 由match函数所匹配的字符串的长度。 | |
RS | 记录分隔符(默认是一个换行符)。 | |
RSTART | 由match函数所匹配的字符串的第一个位置。 | |
SUBSEP | 数组下标分隔符(默认值是/034)。 |
4.1 环境变量示例
4.1.1 NR 获取当前记录的索引
4.1.2 NF`打印一行中的最后一个字段
```shell
echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $NF}'
f3
f5
```
```shell
echo -e "line1 f2 f3\n line2 f4 f5" | awk '{print $(NF-1)}'
f2
f4```
4.1.3 使用$打印一行中指定位置的字段
印每一行的第二和第三个字段:
4.1.4 统计行数END{ print NR }
统计文件中的行数:
思路:可以使用END语句块,在读入每一行的时,awk会将NR更新为对应的行号,当到达最后一行NR的值就是最后一行的行号,所以END语句块中的NR就是文件的行数。
4.1.5 累加每一行中某一列的值
一个每一行中第一个字段值累加的例子:
5. awk运算符
5.1. awk 运算符合集
Table 2. 运算符
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ ~! | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / & | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
in | 数组成员 |
5.1.1 运算符AND 使用范例
5.2. 匹配操作符(~)
用来在记录或者域内匹配正则表达式。如$ awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。
5.3. 比较表达式
conditional expression1 ? expression2: expression3,例如:$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一个域大于第三个域,$1就赋值给max,否则$3就赋值给max。
$ awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。
$ awk '$1 > 5 && $2 < 10' test,如果第一个域大于5,并且第二个域小于10,则打印这些行。
6. 记录和域
6.1. 记录
记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。
$0变量:它指的是整条记录。如$ awk '{print $0}' test将输出test文件中的所有记录。
变量NR:一个计数器,每处理完一条记录,NR的值就增加1。如$ awk '{print NR,$0}' test将输出test文件中所有记录,并在记录前显示记录号。
6.2. 域
6.3. 域分隔符
内建变量FS保存输入域分隔符的值,默认是空格或tab。我们可以通过-F命令行选项修改FS的值。如$ awk -F: '{print $1,$5}' test将打印以冒号为分隔符的第一,第五列的内容。
可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中,如$awk -F'[:/t]' '{print $1,$3}' test,表示以空格、冒号和tab作为分隔符。
输出域的分隔符默认是一个空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5间的逗号就是OFS的值。
7. gawk专用正则表达式元字符
一般通用的元字符集就不讲了,可参考我的Sed和Grep学习笔记。以下几个是gawk专用的,不适合unix版本的awk。
7.1 AWK中使用正则表达式
wk的命令格式
首先需要明确awk的命令格式,这样才能知道正则表达式应该放在哪里。
# awk 'pattern {action}' filename
正则表达式放在哪?
根据上面的命令格式可知,正则表达式应该放在‘patten’这个位置。
在使用正则Pattern时,若没有指定操作,则单个正则表达式将对整行进行模式匹配,并打印出所匹配的行。
匹配操作符
匹配操作符(~) 用于对记录或字段的表达式进行匹配。 例如,找出当前目录下文件所有者为root的文件:
7.1.1 awk所支持的正则表达式元字符
更详细内容可以查看官网:http://www.gnu.org/software/gawk/manual/html_node/Regexp-Operator-Details.html
字符 | 含义 |
---|---|
\
|
依照下列规则匹配: 在非特殊字符之前的反斜杠表示下一个字符是特殊字符,不能按照字面理解。例如,前面没有 "\" 的 "b" 通常匹配小写字母 "b",即字符会被作为字面理解,无论它出现在哪里。但如果前面加了 "\",它将不再匹配任何字符,而是表示一个字符边界。 在特殊字符之前的反斜杠表示下一个字符不是特殊字符,应该按照字面理解。详情请参阅下文中的 "转义(Escaping)" 部分。 如果你想将字符串传递给 RegExp 构造函数,不要忘记在字符串字面量中反斜杠是转义字符。所以为了在模式中添加一个反斜杠,你需要在字符串字面量中转义它。 |
^
|
匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。 例如, 当 ' |
$
|
匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。 例如, |
*
|
匹配前一个表达式 0 次或多次。等价于 例如, |
+
|
匹配前面一个表达式 1 次或者多次。等价于 例如, |
?
|
匹配前面一个表达式 0 次或者 1 次。等价于 例如, 如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。例如,对 "123abc" 使用 还用于先行断言中,如本表的 |
.
|
(小数点)默认匹配除换行符之外的任何单个字符。 例如, 如果 |
(x)
|
像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为捕获括号。 模式 |
(?:x)
|
匹配 'x' 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 |
x(?=y)
|
匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言。 例如,/Jack(?=Sprat)/会匹配到'Jack'仅当它后面跟着'Sprat'。/Jack(?=Sprat|Frost)/匹配‘Jack’仅当它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。 |
(?<=y) x
|
匹配'x'仅当'x'前面是'y'.这种叫做后行断言。 例如,/(?<=Jack)Sprat/会匹配到' Sprat '仅仅当它前面是' Jack '。/(?<=Jack|Tom)Sprat/匹配‘ Sprat ’仅仅当它前面是'Jack'或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。 |
x(?!y)
|
仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。 例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!\.)/ 匹配一个数字。正则表达式/\d+(?!\.)/.exec("3.141")匹配‘141’而不是‘3.141’ |
(?<!y)x
|
仅仅当'x'前面不是'y'时匹配'x',这被称为反向否定查找。 例如, 仅仅当这个数字前面没有负号的时候, |
x|y
|
匹配‘x’或者‘y’。 例如,/green|red/匹配“green apple”中的‘green’和“red apple”中的‘red’ |
{n}
|
n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。 比如, /a{2}/ 不会匹配“candy”中的'a',但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个'a'。 |
{n,}
|
n是一个正整数,匹配前一个字符至少出现了n次。 例如, /a{2,}/ 匹配 "aa", "aaaa" 和 "aaaaa" 但是不匹配 "a"。 |
{n,m}
|
n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。 例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |
[xyz]
|
一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。 例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/与字符串“test.i.ng”匹配。 |
[^xyz]
|
一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。 例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。 |
[\b]
|
匹配一个退格(U+0008)。(不要和\b混淆了。) |
\b
|
匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者前面跟其他“字”字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的字边界。换句话说,一个匹配的词的边界的内容的长度是0。(不要和[\b]混淆了) 使用"moon"举例: 注意: JavaScript的正则表达式引擎将特定的字符集定义为“字”字符。不在该集合中的任何字符都被认为是一个断词。这组字符相当有限:它只包括大写和小写的罗马字母,十进制数字和下划线字符。不幸的是,重要的字符,例如“é”或“ü”,被视为断词。 |
\B
|
匹配一个非单词边界。匹配如下几种情况:
例如,/\B../匹配"noonday"中的'oo', 而/y\B../匹配"possibly yesterday"中的’yes‘ |
\cX
|
当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符。 例如, |
\d
|
匹配一个数字 例如, |
\D
|
匹配一个非数字字符 例如, |
\f
|
匹配一个换页符 (U+000C)。 |
\n
|
匹配一个换行符 (U+000A)。 |
\r
|
匹配一个回车符 (U+000D)。 |
\s
|
匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。 例如, 经测试,\s不匹配"\u180e",在当前版本Chrome(v80.0.3987.122)和Firefox(76.0.1)控制台输入/\s/.test("\u180e")均返回false。 |
\S
|
匹配一个非空白字符。等价于 例如, |
\t
|
匹配一个水平制表符 (U+0009)。 |
\v
|
匹配一个垂直制表符 (U+000B)。 |
\w
|
匹配一个单字字符(字母、数字或者下划线)。等价于 例如, |
\W
|
匹配一个非单字字符。等价于 例如, |
\n
|
在正则表达式中,它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)。 比如 |
\0
|
匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 \0<digits> 是一个八进制转义序列。
|
\xhh
|
匹配一个两位十六进制数(\x00-\xFF)表示的字符。 |
\uhhhh
|
匹配一个四位十六进制数表示的 UTF-16 代码单元。 |
|
(仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。 |
注意问题
正则表达式与通配符是完全不一样的东西!通配符代表的是bash操作接口的一个功能,但正则表达式是一种字符串处理的表达方式!这两者要分清才行。
http://www.gnu.org/software/gawk/manual/html_node/Regexp.html#Regexp
8. POSIX字符集
9. 范围模板
范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。如果有一个模板没出现,则匹配到开头或末尾。如$ awk '/root/,/mysql/' test将显示root第一次出现到mysql第一次出现之间的所有行。
10. 几个实例
$ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行。
$ awk '/^[ns]/{print $1}' test-----如果记录以n或s开头,就打印这个记录。
$ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一个域以两个数字结束就打印这个记录。
$ awk '$1 == 100 || $2 < 50' test-----如果第一个或等于100或者第二个域小于50,则打印该行。
$ awk '$1 != 10' test-----如果第一个域不等于10就打印该行。
$ awk '/test/{print $1 + 10}' test-----如果记录包含正则表达式test,则第一个域加10并打印出来。
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值。
$ awk '/^root/,/^mysql/' test----打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。
10.1. 一个验证passwd文件有效性的例子
$ cat /etc/passwd | awk -F: '/
NF != 7{/
printf("line %d,does not have 7 fields:%s/n",NR,$0)}/
$1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %s/n,NR,$0)}/
$2 == "*" {printf("line %d, no password: %s/n",NR,$0)}'
cat把结果输出给awk,awk把域之间的分隔符设为冒号。 |
|
如果域的数量(NF)不等于7,就执行下面的程序。 |
|
printf打印字符串"line ?? does not have 7 fields",并显示该条记录。 |
|
如果第一个域没有包含任何字母和数字,printf打印“no alpha and numeric user id" ,并显示记录数和记录。 |
|
如果第二个域是一个星号,就打印字符串“no passwd”,紧跟着显示记录数和记录本身。 |
11. awk编程
11.1. 变量
11.1.1 赋值格式
11.1.2 awk可以在命令行中给变量赋值,然后将这个变量传输给awk脚本
11.1.3 域变量也可被赋值和修改
11.1.4 内建变量的使用
11.2. BEGIN模块
11.3. END模块
11.4. 重定向和管道
11.4.1 awk可使用shell的重定向符进行重定向输出
getline 介绍: http://www.gnu.org/software/gawk/manual/html_node/Plain-Getline.html
getline函数得到下一行可能的返回值为:
1 如果能够读取一行。
0 如果到了文件末尾。
-1 如果遇到错误。从文件中读取
getline函数除了能读取正常的输入流外,还可以从文件或管道中读取。
while((getline<"filepath")>0)将输入赋给一个变量
读取下一行并赋值给变量input:
getline input从管道读取输入
执行一个命令并将结果用管道输送到getline。
"who am i"|getline
当一个命令的输出结果被用管道输送给getline且包含多个行时,必须创建一个循环来执行getline。
while("who"|getline)
who_out[++i]=$0
11.4.2 可以在awk中打开一个管道,且同一时刻只能有一个管道存在
11.4.3 通过close()可关闭管道
如:$ awk '{print $1, $2 | "sort" }' test END {close("sort")}。awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。
11.4.4 system函数可以在awk中执行linux的命令
如:$ awk 'BEGIN{system("clear")'。
11.4.5 flush函数用以刷新输出缓冲区
如果没有参数,就刷新标准输出的缓冲区,如果以空字符串为参数,如fflush(""),则刷新所有文件和管道的输出缓冲区。
11.5. 条件语句
官网查看详情:http://www.gnu.org/software/gawk/manual/html_node/If-Statement.html
awk中的条件语句是从C语言中借鉴过来的,可控制程序的流程。
11.5.1. if语句
格式:{if (expression){statement; statement; ...}}
$ awk '{if ($1 <$2) print $2 "too high"}' test。如果第一个域小于第二个域则打印。
$ awk '{if ($1 < $2) {count++; print "ok"}}' test.如果第一个域小于第二个域,则count加一,并打印ok。
11.5.2. if/else语句,用于双重判断。
格式:{if (expression){statement; statement; ...}else{statement; statement; ...}}
$ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test。如果$1大于100则打印$1 bad,否则打印ok。
$ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test。如果$1大于100,则count加一,并打印$1,否则count减一,并打印$1。
11.5.3. if/else else if语句,用于多重判断。
格式:{if (expression){statement; statement; ...}else if (expression){statement; statement; ...}else if (expression){statement; statement; ...}else {statement; statement; ...}}
11.6. 循环
awk有三种循环:while循环;for循环;special for循环。
$ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test。变量的初始值为1,若i小于可等于NF(记录中域的个数),则执行打印语句,且i增加1。直到i的值大于NF.
$ awk '{for (i = 1; i<NF; i++) print NF,$i}' test。作用同上。
breadkcontinue语句。break用于在满足条件的情况下跳出循环;continue用于在满足条件的情况下忽略后面的语句,直接返回循环的顶端。如:
{for ( x=3; x<=NF; x++) if ($x<0){print "Bottomed out!"; break}} {for ( x=3; x<=NF; x++)if ($x==0){print "Get next item"; continue}}
next语句从输入文件中读取一行,然后从头开始执行awk脚本。如:
{if ($1 ~/test/){next}else {print} }
exit语句用于结束awk程序,但不会略过END块。退出状态为0代表成功,非零值表示出错。
11.7. 数组
官网链接:http://www.gnu.org/software/gawk/manual/html_node/Arrays.html
11.7.1. 下标与关联数组
用变量作为数组下标。如:$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test。数组name中的下标是一个自定义变量x,awk初始化x的值为0,在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。
special for循环用于读取关联数组中的元素。格式如下:
- 数组的顺序得不到保证
http://www.gnu.org/software/gawk/manual/html_node/Scanning-an-Array.html
{for (item in arrayname){print arrayname[item]}
}
$ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test。打印有值的数组元素。打印的顺序是随机的。
- 注意下面的用法尽量避免
- awk 'BEGIN{
- SUBSEP=":"
- array["a","b:c"]=1 # 下标为“a:b:c”
- array["a:b","c"]=2 #下标同样是“a:b:c”
- for (i in array) print i,array[i]}'
- a:b:c 2 #所以数组元素只有一个
用字符串作为下标。如:count["test"]
用域值作为数组的下标。一种新的for循环方式,for (index_value in array) statement。如:$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test。该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标,第一个域变化,索引就变化。
delete函数用于删除数组元素。如:$ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test。分配给数组line的是第一个域的值,所有记录处理完成后,special for循环将删除每一个元素。
11.8. awk的内建函数
11.8.1. 字符串函数sub&gsub&substr&index&split&toupper&tolower
sub函数匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候。格式如下:
sub (regular expression, substitution string):sub (regular expression, substitution string, target string)
实例:
$ awk '{ sub(/test/, "mytest"); print }' testfile$ awk '{ sub(/test/, "mytest"); $1}; print }' testfile
第一个例子在整个记录中匹配,替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub
第二个例子在整个记录的第一个域中进行匹配,替换只发生在第一次匹配发生的时候。
gsub函数作用如sub,但它在整个文档中进行匹配。格式如下:
gsub (regular expression, substitution string)gsub (regular expression, substitution string, target string)
实例:
$ awk '{ gsub(/test/, "mytest"); print }' testfile$ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile
第一个例子在整个文档中匹配test,匹配的都被替换成mytest。
第二个例子在整个文档的第一个域中匹配,所有匹配的都被替换成mytest。
index函数返回子字符串第一次被匹配的位置,偏移量从位置1开始。格式如下:
index(string, substring)
实例:
$ awk '{ print index("test", "mytest") }' testfile
实例返回test在mytest的位置,结果应该是3。
length函数返回记录的字符数。格式如下:
length( string )length
实例:
$ awk '{ print length( "test" ) }' $ awk '{ print length }' testfile
第一个实例返回test字符串的长度。
第二个实例返回testfile文件中第条记录的字符数。
substr函数返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串。格式如下:
substr( string, starting position )substr( string, starting position, length of string )
实例:
$ awk '{ print substr( "hello world", 7,11 ) }'
上例截取了world子字符串。
match函数返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串。函数格式如下:
match( string, regular expression )
实例:
$ awk '{start=match("this is a test",/[a-z]+$/); print start}'$ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
第一个实例打印以连续小写字符结尾的开始位置,这里是11。
第二个实例还打印RSTART和RLENGTH变量,这里是11(start),11(RSTART),4(RLENGTH)。
toupper和tolower函数可用于字符串大小间的转换,该功能只在gawk中有效。格式如下:
toupper( string )tolower( string )
实例:
$ awk '{ print toupper("test"), tolower("TEST") }'
split函数可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割。格式如下:
split( string, array, field separator )split( string, array )
实例:
$ awk '{ split( "20:18:00", time, ":" ); print time[2] }'
上例把时间按冒号分割到time数组内,并显示第二个数组元素18。
11.8.2. 时间函数
systime函数返回从1970年1月1日开始到当前时间(不计闰年)的整秒数。格式如下:
systime()
实例:
$ awk '{ now = systime(); print now }'
strftime函数使用C库中的strftime函数格式化时间。格式如下:
systime( [format specification][,timestamp] )
Table 3. 日期和时间格式说明符
格式 描述 %a 星期几的缩写(Sun) %A 星期几的完整写法(Sunday) %b 月名的缩写(Oct) %B 月名的完整写法(October) %c 本地日期和时间 %d 十进制日期 %D 日期 08/20/99 %e 日期,如果只有一位会补上一个空格 %H 用十进制表示24小时格式的小时 %I 用十进制表示12小时格式的小时 %j 从1月1日起一年中的第几天 %m 十进制表示的月份 %M 十进制表示的分钟 %p 12小时表示法(AM/PM) %S 十进制表示的秒 %U 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) %w 十进制表示的星期几(星期天是0) %W 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) %x 重新设置本地日期(08/20/99) %X 重新设置本地时间(12:00:00) %y 两位数字表示的年(99) %Y 当前月份 %Z 时区(PDT) %% 百分号(%) 实例:
$ awk '{ now=strftime( "%D", systime() ); print now }'$ awk '{ now=strftime("%m/%d/%y"); print now }'
11.8.3. 内建数学函数
Table 4.
函数名称 | 返回值 |
---|---|
atan2(x,y) | y,x范围内的余切 |
cos(x) | 余弦函数 |
exp(x) | 求幂 |
int(x) | 取整 |
log(x) | 自然对数 |
rand() | 随机数 |
sin(x) | 正弦 |
sqrt(x) | 平方根 |
srand(x) | x是rand()函数的种子 |
int(x) | 取整,过程没有舍入 |
rand() | 产生一个大于等于0而小于1的随机数 |
11.8.4. 自定义函数
在awk中还可自定义函数,格式如下:
function name ( parameter, parameter, parameter, ... ) {statementsreturn expression # the return statement and expression are optional}
Linux 文件管理-文件内容-分析工具【awk】脚本处理文本和数据-Linux 文本操作三剑客相关推荐
- Linux 文件管理-文件内容-读取工具-【cattac】连接多个文件并打印到标准输出
cat === 连接多个文件并打印到标准输出. 概要 cat [OPTION]... [FILE]... 主要用途 显示文件内容,如果没有文件或文件为-则读取标准输入. 将多个文件的内容进行连接并打印 ...
- 2019-8-20 [Linux] 6.Shell的基本操作 查看 改变 列出 阅读开头/结尾 循环查看 阅读工具less 查找文件内容 文本分析工具AWK 文本编辑工具SED文件find 帮助man
文章目录 6.linuxShell的基本操作 6.1 查看目录和文件 6.1.1 显示当前目录:pwd 6.1.2 改变目录:cd 6.1.3 列出目录内容:ls 1) 查看列表信息 以及详细信息 2 ...
- linux下grep文件内容搜索工具及基本正则表达式详解
linux下grep文件内容搜索工具及基本正则表达式详解 grep命令: 根据模式(文本字符和基本正则表达式的元字符组合而成之匹配条件)搜索文本, 并将符合模式的文本行显示出来. 格式:grep [选 ...
- Linux下常用日志分析工具
Linux下常用日志分析工具 Logcheck简介 对于拥有大量账户.系统繁忙的Linux系统而言,其日志文件是极其庞大的,很多没有用的信息会将值得注意的信息淹没,给用户分析日志带来了很大的不便.现在 ...
- 常用Linux网络/内存/磁盘分析工具
Centos查看网卡.CPU.内存等使用率 # watch more /proc/net/dev 性能分析和监控工具 uptime dmesg | tail vmstat 1 mpstat -P AL ...
- linux清除文件内容 ,Linux清除文件内容的几种方法
# 清空或删除大文件内容的五种方法: # 法一:通过重定向到 Null 来清空文件内容 $ >test.sh # 法二:使用 'true' 命令重定向来清空文件 $ true > test ...
- Linux查找文件内容
2019独角兽企业重金招聘Python工程师标准>>> Linux查找文件内容 使用vim命令查找文件内容 我们可以使用/string命令来向前(Forward)查找字符串strin ...
- 【PC工具】更新win10关闭更新工具,接速度最快最好用的文件内容搜索工具:searchmyfiles...
微信关注 "DLGG创客DIY" 设为"星标",重磅干货,第一时间送达. 今天一个朋友向我咨询win10更新的关闭方法,主要是因为她的办公电脑经常提示更新,并且 ...
- 【PC工具】更新速度最快最好用的文件内容搜索工具:searchmyfiles
微信关注 "DLGG创客DIY" 设为"星标",重磅干货,第一时间送达. 上次分享了everything及everything文件内容的查找方法,搜索文件名没问 ...
最新文章
- 计算机教师个人总结及自评,教师个人自评总结
- 最后一周 | 微生物组-宏基因组分析第8期(报名直播课免费参加线下2020.7)
- matlab编程小结
- ppt矩形里面的图片怎么放大缩小_两年没做PPT,这些功能让我老泪纵横。
- 令人惊叹的前端路由原理解析和实现方式
- DAY5-小别-2018-1-15
- jzoj3846-七天使的通讯【二分图判定】
- ASP.NET.CORE发布后启动网站出现500.19-0x8007000d错误解决方法
- Oracle数据库的备份
- Enterprise Library 4.1 快速上手(图)
- hbase 集群(完全分布式)方式安装
- jsf el 表达式_JSF表达式语言– JSF EL
- java第一个helloworld_Java第一个程序--HelloWorld
- 悟空CRM的环境搭建
- 树莓派 kali系统默认密码
- 【Python】10行代码获取海贼王最新目录
- qq邮件 外发服务器设置,利用腾讯企业邮箱配置外发邮件服务
- Java 时间差运算工具函数(时间戳运算)
- Servlet获取Excel中数据的两种方式
- 编写c语言的开篇——Hello World
热门文章
- Java堆外内存泄露分析
- 意男子16年秘建地下神庙 堪称世界第八奇迹(转)
- 用Java写句情话_哄对象最好用的22句情话,句句甜到心里
- JavaScript验证码示例
- SpringBoot教程(十六) | SpringBoot集成swagger(全网最全)
- Python读取CSV文件写入Mysql数据库
- iNFTnews | 百度携手中国航天推出全新NFT作品,开启“未来太空”探索之旅
- Linux之expect命令,以及实战使用!!!
- ROG游戏手机6正式发布 跑分高达112万
- Ajax跨域和JSONP