my_study_rst’s 学习笔记¶
我自己对rst文档的学习笔记
基础语法¶
1 简介¶
1.0 关于awk语言¶
awk的基本功能是搜索包含特定模式的行(或其他文本单元)的文件。当一行符合其中一个模式时,awk将在该行上执行指定的操作。 awk继续以这种方式处理输入行,直到达到输入文件的末尾。
awk中的程序与大多数其他语言中的程序不同,因为awk程序是数据驱动的(即,描述要使用的数据,然后在找到它时执行什么操作)。大多数其他语言是程序性的;你必须详细描述程序应该采取的每一步。在使用程序语言时,通常要更清楚地描述程序将要处理的数据。出于这个原因,awk程序通常很容易读写。
当你运行awk时,你指定了一个awk程序来告诉awk该怎么做。该程序由一系列规则组成(它也可能包含函数定义,我们现在将忽略的高级功能;请参阅用户定义)。每个规则指定一个要搜索的模式和一个寻找模式的操作。
在语法上,一个规则由一个模式和一个动作组成。这个动作用大括号括起来以便将它从模式中分离出来。换行通常分开规则。因此,一个awk程序看起来像这样:
pattern { action }
pattern { action }
…
1.1 如何运行awk¶
运行一个简单的awk是这个样子的
awk 'program' input-file1 input-file2 …
1.1.1 运行awk没有输入文件¶
如果这是一个简单的打印工作,不需要输入,我们可以使用如下方式:
[root@centos74 test]$ awk 'BEGIN {print "hello world"}'
hello world
1.1.2 运行一个长命令¶
我们如果代码过于长的话, 可以考虑把代码写入到文件中去,可以参考如下用法:
[root@centos74 test]$ vim advice.awk
[root@centos74 test]$ cat advice.awk
BEGIN { print "hellow world 2" }
[root@centos74 test]$ awk -f advice.awk
hellow world 2
1.1.3 执行awk脚本文件¶
上面的awk脚本已经写入到文件了,但是不是太完善, 我们可以改下为如下:
[root@centos74 test]$ cp advice.awk advice2.awk
[root@centos74 test]$ vim advice2.awk
[root@centos74 test]$ cat advice2.awk
#!/usr/bin/awk -f
BEGIN { print "hellow world 3" }
[root@centos74 test]$ chmod a+x advice2.awk
[root@centos74 test]$ ./advice2.awk
hellow world 3
Note
上面的`#!/usr/bin/awk -f` 是Shebang机制,正如写bash脚本需要加`#!/usr/bin/bash`一样的
1.1.4 在awk脚本中添加注释¶
添加注释和bash一样。 需要在行首添加一个#即可
[root@centos74 test]$ cp advice2.awk advice3.awk
[root@centos74 test]$ vim advice3.awk
[root@centos74 test]$ cat advice3.awk
#!/usr/bin/awk -f
# this is a test script
BEGIN { print "hellow world 3" } # this is a comment
[root@centos74 test]$ ./advice3.awk
hellow world 3
Warning
这个再次强调下,“# this is test script”是注释,第一行虽然也是“#”打头,但不是注释。是Shebang机制要求的。
1.1.5 shell下的引号问题¶
awk的`progra`语句用单引号引起来,里面用到字符串使用双引号引起来。
[root@centos74 test]$ awk 'BEGIN { print "this is a quote" }'
this is a quote
如果内部用到的字符串使用了单引号,可以采取如下措施:
[root@centos74 test]$ awk -v sq="'" 'BEGIN { print "Here is a single quote <" sq ">" }'
Here is a single quote <'>
上面使用了一个变量sq来表示单引号,里面引用这个变量就可以了。避免了各种转义引起的繁琐问题。
1.2 样例数据¶
为了后续的实验方便,这里提供几个样例文件:
[root@centos74 test]$ cat mail-list Amelia 555-5553 amelia.zodiacusque@gmail.com F Anthony 555-3412 anthony.asserturo@hotmail.com A Becky 555-7685 becky.algebrarum@gmail.com A Bill 555-1675 bill.drowning@hotmail.com A Broderick 555-0542 broderick.aliquotiens@yahoo.com R Camilla 555-2912 camilla.infusarum@skynet.be R Fabius 555-1234 fabius.undevicesimus@ucb.edu F Julie 555-6699 julie.perscrutabor@skeeve.com F Martin 555-6480 martin.codicibus@hotmail.com A Samuel 555-3430 samuel.lanceolis@shu.edu A Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R [root@centos74 test]$ cat inventory-shipped Jan 13 25 15 115 Feb 15 32 24 226 Mar 15 24 34 228 Apr 31 52 63 420 May 16 34 29 208 Jun 31 42 75 492 Jul 24 34 67 436 Aug 15 34 47 316 Sep 13 55 37 277 Oct 29 54 68 525 Nov 20 87 82 577 Dec 17 35 61 401
Jan 21 36 64 620 Feb 26 58 80 652 Mar 24 75 70 495 Apr 21 70 74 514
1.3 一些简单的awk使用¶
找到mail-list文件中,包含了li字符串的行:
[root@centos74 test]$ awk '/li/ {print $0}' mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Julie 555-6699 julie.perscrutabor@skeeve.com F
Samuel 555-3430 samuel.lanceolis@shu.edu A
“/li/”是个正则表达式,默认是匹配行的,如果行满足就执行后面{}里面的代码。
找到行长度大于40的行,并显示长度:
[root@centos74 test]$ awk 'length($0) > 40 { print length($0) , $0} ' mail-list
59 Amelia 555-5553 amelia.zodiacusque@gmail.com F
59 Anthony 555-3412 anthony.asserturo@hotmail.com A
59 Becky 555-7685 becky.algebrarum@gmail.com A
59 Bill 555-1675 bill.drowning@hotmail.com A
59 Broderick 555-0542 broderick.aliquotiens@yahoo.com R
59 Camilla 555-2912 camilla.infusarum@skynet.be R
59 Fabius 555-1234 fabius.undevicesimus@ucb.edu F
59 Julie 555-6699 julie.perscrutabor@skeeve.com F
59 Martin 555-6480 martin.codicibus@hotmail.com A
59 Samuel 555-3430 samuel.lanceolis@shu.edu A
59 Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
很不巧,上面我们的数据非常规整,长度都大于40且长度一样。
打印文件的偶数行:
[root@centos74 test]$ awk 'NR % 2 == 0' mail-list
Anthony 555-3412 anthony.asserturo@hotmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Camilla 555-2912 camilla.infusarum@skynet.be R
Julie 555-6699 julie.perscrutabor@skeeve.com F
Samuel 555-3430 samuel.lanceolis@shu.edu A
我这里没有指定要打印数据, 默认是打印$0,也就是整行数据
1.4 两个规则样例¶
上面的样例,我们都使用的单一个条件匹配就打印了。 如果条件比较复杂就需要多个条件来控制了。
[root@centos74 test]$ awk '/12/ {print $0 }
> /21/ {print $0 } ' mail-list inventory-shipped
Anthony 555-3412 anthony.asserturo@hotmail.com A
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
Jan 21 36 64 620
Apr 21 70 74 514
写了2组,每组都是一个pattern,一个打印, 如果满足就打印。
1.5 关于awk语句的跨行问题¶
跨行问题很常见的,一行写不完就需要写2行甚至多行。
[root@centos74 test]$ awk 'BEGIN{print "this is a test,this is a test , this is a test \
> this is a test " }'
this is a test,this is a test , this is a test this is a test
对于普通的字符串需要换行的时候,我们需要添加``去转义回车符号。 但是对于如下字符我们没有必要去添加转义符号:
, { ? : || && do else
上面的字符我们没有必要去添加转义符号, 还有一些awk内置的关键词也是如此。如果一行写不下。直接回车写下一行就是了。
2 运行awk¶
2.1 调用awk¶
在前面我们已经提到了awk的调用方法。详细使用如下:
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk [ POSIX or GNU style options ] [ -- ] program-text file ...
2.2 命令行选项¶
awk即是一门语言,也是一个命令,是支持命令行的选项的。
-F | 指定字段分隔符 |
--field-separator | |
指定字段分隔符,同-F | |
-f | 指定源awk脚本文件 |
--file | 指定源awk脚本文件,同-f |
-v | 设定变量,使用-v var1=”test” |
--debug | 调试awk |
-l | 加载扩展 |
--load | 加载扩展,同-l |
2.3 通过标准输出流作为awk输入¶
使用重定向技术,具体直接看样例把
[root@centos74 test]$ cat mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
[root@centos74 test]$ cat mail-list | awk '$1 == "Amelia" {print $0}'
Amelia 555-5553 amelia.zodiacusque@gmail.com F
2.3 AWK环境变量¶
2.3.1 AWKPATH环境变量¶
我这里使用的环境是centos7,机器上带的是gawk。默认的AWKPATH在/usr/share/awk,我们需要修改AWKPATH为`/usr/share/awk`即可
[root@centos74 test]$ vim ~/.bash_profile
[root@centos74 test]$ cat ~/.bash_profile |grep AWK
export AWKPATH="/usr/share/awk"
2.3.2 AWKLIBPATH环境变量¶
AWKLIBPATH的修改同上,只需要设定AWKLIBPATH=”you_lib”
2.4 awk退出码¶
和bash一样, 正确退出是返回0的,错误退出返回其他
2.5 包含其他文件到程序中¶
想在一个awk程序文件中代用另一个文件的程序,需要使用include语句,有点类似c语言的风格的。
[root@centos74 test]$ vim test1.awk
[root@centos74 test]$ rm -rf test1.awk test2.awk
[root@centos74 test]$ vim test1.awk
[root@centos74 test]$ cat test1.awk
BEGIN {
print " this is test1.awk"
}
[root@centos74 test]$ vim test2.awk
[root@centos74 test]$ cat test2.awk
@include "test1.awk"
BEGIN {
print " this is test2.awk"
}
[root@centos74 test]$ gawk -f test2.awk
this is test1.awk
this is test2.awk
3 正则表达式¶
awk是支持正则表达式的。
3.1 如何使用正则表达式¶
[root@centos74 test]$ awk ' $1 ~ /li/ {print $2}' mail-list
555-5553
555-6699
这个例子就是使用了正则表达式,使用”/li/”去匹配第一个字段中包含了”li”的,然后打印出来第二个字段。
3.3 正则表达式元字符¶
\ 用于转义的
^ 用于锚定行首
$ 用于锚定行尾
. 用于单个任意字符
[...] 用于匹配集合单个字符
[^...] 用于匹配除了几何以外的字符
| 用于配合左侧,或者右侧
() 改变优先级的,作为一个整体
* 前面的分组或者字符任意次数。长配合.使用
+ 用于匹配前面的分组或者字符至少一次
? 用于匹配前面的分组或者字符一次或者0次。
{n} 用于匹配n次
{n,} 用于匹配至少n次
{m,n} 用于匹配m次到n次
3.4 一些中括号表达式¶
[:alnum:] 字母数字
[:alpha:] 字母
[:blank:] 空格和tab
[:cntrl:] 控制字符
[:digit:] 数字
[:lower:] 小写
[:upper:] 大写
3.5 匹配文本¶
使用正则去匹配文本
[root@centos74 test]$ echo "aaaabcd" |awk '{sub(/a+/,"<A>"); print $0}'
<A>bcd
这个使用到了awk内置的一个函数sub行数,第一个参数是正则,第个是替换的结果。
3.6 使用动态的正则表达式¶
动态的正则表达式就是把使用的正则表达式存起来。用的使用启用即可
[root@centos74 test]$ echo "aaaabcd" |awk 'BEGIN {test_re="a+"} $0 ~ test_re {print $0}'
aaaabcd
3.7 大小写敏感匹配¶
正则表达式是对大小写敏感的。如果不想对敏感,可以考虑使用函数转成小写在比较,或者指定忽略大小写。
[root@centos74 test]$ echo "Abc" |awk ' $0 ~ "ab" {print $0}'
[root@centos74 test]$ echo "Abc" |awk ' $0 ~ "Ab" {print $0}'
Abc
[root@centos74 test]$ echo "Abc" |awk ' tolower($0) ~ "ab" {print $0}'
Abc
[root@centos74 test]$ echo "Abc" |awk 'BEGIN{IGNORECASE =1 } $0 ~ "ab" {print $0}'
Abc
4 读取输入文件¶
4.1 分割输入文件¶
4.1.1 标准awk的记录分割¶
awk中默认的记录分隔符号是换行,也就是一行一个记录。如果我们不想使用默认的记录分割,可以指定RS.
[root@centos74 test]$ awk 'BEGIN {RS="u"} NR <= 3 {print $0 }' mail-list
Amelia 555-5553 amelia.zodiac
sq
e@gmail.com F
Anthony 555-3412 anthony.assert
[root@centos74 test]$ head -n 3 mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
NR<=3指定了如果当前记录数量小于等于3,RS代表记录分隔符。
4.1.2 gawk记录分割使用多个分隔符¶
使用大小字母去分割一个字符串为多个记录
[root@centos74 test]$ echo "recode 1 AAAA recode 2 BBBB recode 3" | awk 'BEGIN {RS="\n|( *[[:upper:]]+ *)"} {print $0}'
recode 1
recode 2
recode 3
4.2 测试字段¶
根据某个字段去作为判定条件
[root@centos74 test]$ awk '$1 ~ /li/ {print $0}' mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Julie 555-6699 julie.perscrutabor@skeeve.com F
4.3 非恒定的字段个数¶
awk中内置了一个变量来存储单个记录的字段个数,NF(numer of filed)。
[root@centos74 test]$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda3 50264616 18816916 28871316 40% /
devtmpfs 1001532 0 1001532 0% /dev
tmpfs 1015956 0 1015956 0% /dev/shm
tmpfs 1015956 17596 998360 2% /run
tmpfs 1015956 0 1015956 0% /sys/fs/cgroup
/dev/sda5 20027216 315120 18671712 2% /app
/dev/sda1 999320 192360 738148 21% /boot
tmpfs 203192 36 203156 1% /run/user/0
[root@centos74 test]$ df |awk '{print $NF}'
on
/
/dev
/dev/shm
/run
/sys/fs/cgroup
/app
/boot
我们可以看出来。 我想去导入第二列的时候, 不用数数这是第几个。NF存储的是记录的属性个数,$NF就是最后一个属性列
4.4 字段的一些运算¶
[root@centos74 test]$ awk ' {$6 = ($5 + $4 + 20 ) * 10 ; print $6}' inventory-shipped
4.5 指定字段分隔符¶
记录的默认分割符号是换行,字段的默认的分割符号是空格,当然也是可以修改的。
4.5.1 修改字段分隔符¶
修改默认的字符分割符号
[root@centos74 test]$ echo "a,b,c,d" | awk -F "," '{print $2}'
b
[root@centos74 test]$ echo "a,b,c,d" | awk 'BEGIN{FS=","}{print $2}'
b
第一种方式是通过命令行参数方式设定的,简单方便。
4.5.2 多个字段分割符号¶
有时候我们分割字段的时候,既想tab分割又想空格分割,可以考虑如下方案:
[root@centos74 test]$ echo "a,b,c d:f" | awk 'BEGIN{FS="[ ,]" } {print "$1="$1, "$2="$2 , "$3="$3,"$4="$4}'
$1=a $2=b $3=c $4=d:f
4.5.3 分割记录单个字符就是一个字段¶
有时候我们需要将一个单词拆成一个一个字符的。可以参考如下:
[root@centos74 test]$ echo "adsjfsdj" |awk 'BEGIN{FS=""} {print $1,$NF}'
a j
4.5.4 合并所有行为但一行, 每行作为一个属性字段¶
方法比较简单就是设定字段的分隔符号为`n`即可。
4.6 读取固定宽度的数据¶
4.6.1 处理固定宽度的数据¶
linux下好多命令输出都是固定宽度的,比如w命令,如何提取这些数据呢?
[root@centos74 test]$ w | awk 'BEw | awk 'BEGIN { FIELDWIDTHS="9 6 10 6 7 7 35"}
NR > 2 {
print $1 ,$2 $5
}'
root :0 Thu
root tty2 Fri
root pts/0 08:
root pts/1 09:
4.6.1 固定字段宽度的一些问题¶
我们固定了字段的宽度,但是输入数据刚刚好,那是非常好的, 有时候可能传过来的多了或者少了。这种情况gawk是如何处理的。
- 刚好的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbcccc”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”cccc”
- 缺宽度的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbccc”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”ccc”
- 多宽度的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbccccdd”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”cccc”,多余的dd就被丢弃了。如果想使用可以最后一个字段使用*代替
4.7 csv文件的处理¶
这里有一个csv文件,想提取出来名字和带引号的字段。
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
考虑到引号里面有,所以如果使用,去分割这个csv文件的时候会出错的。
[root@centos74 test]$ vim addresses.csv
[root@centos74 test]$ cat addresses.csv
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
[root@centos74 test]$ vim addresses.awk
[root@centos74 test]$ cat addresses.awk
BEGIN {
FPAT="([^,]+)|(\"[^\"]+\")"
}
{
print "NF=" ,NF
for (i=1;i <=NF; i++){
printf("$%d =<%s>\n" ,i,$i)
}
}
[root@centos74 test]$ gawk -f addresses.awk addresses.csv
NF= 7
$1 =<Robbins>
$2 =<Arnold>
$3 =<"1234 A Pretty Street, NE">
$4 =<MyTown>
$5 =<MyState>
$6 =<12345-6789>
$7 =<USA>
上面的为何就是可以只能的识别出双引号中的逗号呢。 关键就是EPAT的正则表达式。简单说下这个正则表达式把。 “|”跟个2个部分,第二部分代表引号开头,中间是非引号多次,最后一个引号。
4.8 检查awk使用的字段分割方案¶
上面我们提到了几种分割方案
[root@centos74 test]$ echo "abc" |awk 'BEGIN{
if (PROCINFO["FS"] == "FS")
print "BASIC"
else if (PROCINFO["FS"] == "FIELDWIDTHS")
print "FIELDWIDTHS"
else if (PROCINFO["FS"] == "FPAT")
print "FPAT"
else
print "else"
}'
BASIC
5 打印输出¶
5.1 使用print语句¶
使用print比较简单,每个打印的元素用逗号分割即可。
[root@centos74 test]$ awk '{print $1,$2}' mail-list
Amelia 555-5553
Anthony 555-3412
Becky 555-7685
Bill 555-1675
Broderick 555-0542
Camilla 555-2912
Fabius 555-1234
Julie 555-6699
Martin 555-6480
Samuel 555-3430
Jean-Paul 555-2127
5.2 输出分割符号¶
默认的输出字段分割符号是空格, 默认的输出记录分隔符是回车。
[root@centos74 test]$ awk 'BEGIN{OFS=":" ; ORS="\n\n"}{print $1,$2}' mail-list
Amelia:555-5553
Anthony:555-3412
Becky:555-7685
Bill:555-1675
Broderick:555-0542
Camilla:555-2912
Fabius:555-1234
Julie:555-6699
Martin:555-6480
Samuel:555-3430
Jean-Paul:555-2127
控制输出分割符号,可以直接修改OFS(output field seprate),ORS(output field seprate)
5.3 使用printf去输出¶
print打印起来有些格式控制上不是太灵活的。 这个时候就需要printf闪亮登场了。
使用前有必要先给控制符号说下。 基本上和c语言的printf风格一样的。 学起来也是比较轻松的。
%c 单个字符
%d 数字
%e 科学计数表示
%f 浮点数
%g 只能使用科学技术和通用技术表示法
%% 打印%
$s 字符串
- 左边对齐
+ 正负数符号
0 控制前导0
width 控制有效位数
. 控制浮点精度
使用样例
[root@centos74 test]$ echo "15" | awk '{printf "%d\n",$0 }'
15
[root@centos74 test]$ echo "15" | awk '{printf "%3d\n",$0 }'
15
[root@centos74 test]$ echo "15" | awk '{printf "%+3d\n",$0 }'
+15
[root@centos74 test]$ echo "15.1" | awk '{printf "%-3.2f\n",$0 }'
15.10
5.3 重定向print的结果和printf的结果¶
一个文件中有多个属性列,但是我指向提取部分列数据, 且单独分割到一个文件中,可以考虑如下方法。
[root@centos74 test]$ awk '{ print $2 > "phone-list"
print $1 > "name-list" }' mail-list
[root@centos74 test]$ cat phone-list
555-5553
555-3412
555-7685
555-1675
555-0542
555-2912
555-1234
555-6699
555-6480
555-3430
555-2127
[root@centos74 test]$ cat name-list
Amelia
Anthony
Becky
Bill
Broderick
Camilla
Fabius
Julie
Martin
Samuel
Jean-Paul
有时候我们使用awk提取完数据,需要借助bash去完成后续的操作。可以参考如下:
[root@centos74 test]$ awk '{print $1 > "name.unsorted"
> command = "sort -r >name.sorted"
> print $1 | command }' mail-list
用一个变量去存储要重定向的命令。将结果管道给重定向的命令即可。
5.4 指定print的输出¶
我们使用print,printf的时候是可以指定输出位置的, 默认是标准输出的。
[root@centos74 test]$ awk 'BEGIN{prinf "aaa" > "a.txt"}'
6 表达式¶
6.1 常量表达式¶
6.1.1 数字和字符串常量¶
105
"abc"
6.1.2 正则表达式常量¶
if ($0 ~ /barfly/ || $0 ~ /camelot/)
print "found"
6.1.3 自定义的变量¶
awk作为一个编程语言,变量的支持那是必须的啊。
[root@centos74 test]$ awk -v a="test" 'BEGIN{print a}'
test
自定的变量可以使用命令行方式, 也是可以在BEGIN里面去定义。
6.2 使用表示式¶
6.2.1 算数操作¶
awk对算数的支持也是每常完美的
[root@centos74 test]$ vim grades
[root@centos74 test]$ cat grades
Pat 100 97 58
Sandy 84 72 93
Chris 72 92 89
[root@centos74 test]$ awk '{sum=$2+$3+$3; avg=sum/3; print $1,avg}' grades
Pat 98
Sandy 76
Chris 85.3333
6.2.2 字符串操作¶
字符串主要是拼接, 直接写你要拼接的字符串即可。类似bash,不想python语言字符串莱娜姐需要连接符“+” 。
6.2.3 赋值表达式¶
赋值是比较简单的 a=”abd” 即可。
6.2.4 自增表达式¶
这个用法和c语言是一样的。使用`b++`即可完成b变量的自增,
6.3 判定表达式¶
6.3.1 字符串和数值的判定表达式¶
awk中对真假的判定是这样的。 数值类如果是0 就是False, 非0就是True。字符串类如果是没有设置的话就是False,其他为True。
6.3.3 三目表达式¶
直接给样例
[root@centos74 test]$ awk 'BEGIN{a=-1;b= a <=0 ?(++a):a; print b}'
0
[root@centos74 test]$ awk 'BEGIN{a=1;b= a <=0 ?(++a):a; print b}'
1
如果添加成立,就执行第一个语句,否则第二个。 三目表达式是一个ifelse语句的简单写法。
6.4 函数¶
awk 内置一些常用函数,比如计算字符串长度(length),去平方根的函数(sqrt)等等。
7 模式动作和变量¶
7.1 模式元素¶
模式元素主要有如下几种:
/regular expression/ 一个正则表达式
expression 一个单表达式
begpat,endpat 逗号分割的2个模式
BEGIN 开始模式
END 结束模式
BEGINFILE 数据预处理
ENDFILE 数据后处理操作
empty 空,默认匹配所有行
7.1.1 正则表达式作为模式¶
/foo|bar|baz/ { buzzwords++ }
END { print buzzwords, "buzzwords seen" }
7.1.2 算数表达式作为模式¶
awk '$1 == "li" { print $2 }' mail-list
7.1.3 BEGINFILE和ENDFILE¶
这2个模式算是awk提供的钩子函数吧 , BEGINFILE在我们处理文件之前执行, 我们可以在这个模式内部写判断文件权限, 预处理数据工作,ENDFILE这个模式在我们处理完毕文件的时候执行,可以完成后续的工作,比如我们生成一个脚本文件,可以在这里设置后续权限问题的。
7.2 使用SHELL变量¶
shell的变量和awk的变量是不一样的。想在awk中使用shell的变量可以考虑如下方法:
[root@centos74 test]$ var1="abc"
[root@centos74 test]$ awk -v var1=$var1 'BEGIN{print var1}'
abc
7.3 动作¶
通常情况下匹配一个模式,都要采取对应的动作。默认的动作是打印。
7.4 控制语句¶
控制语句是动作的一种。awk中的控制和c基本一样。使用起来也是非常方便的。
7.4.1 for¶
样例1:
awk '
{
for (i = 1; i <= 3; i++)
print $i
}' inventory-shipped
样例2:
for (i in array)
do something with array[i]
7.4.1 switch¶
样例:
while ((c = getopt(ARGC, ARGV, "aksx")) != -1) {
switch (c) {
case "a":
# report size of all files
all_files = TRUE;
break
case "k":
BLOCK_SIZE = 1024 # 1K block size
break
case "s":
# do sums only
sum_only = TRUE
break
case "x":
# don't cross filesystems
fts_flags = or(fts_flags, FTS_XDEV)
break
case "?":
default:
usage()
break
}
}
7.4.1 break¶
样例:
# find smallest divisor of num
{
num = $1
for (divisor = 2; divisor * divisor <= num; divisor++) {
if (num % divisor == 0)
break
}
if (num % divisor == 0)
printf "Smallest divisor of %d is %d\n", num, divisor
else
printf "%d is prime\n", num
}
7.4.1 continue¶
样例:
BEGIN {
for (x = 0; x <= 20; x++) {
if (x == 5)
continue
printf "%d ", x
}
print ""
}
7.4.1 next¶
next 这个用法在c中没有,这个的意思就是立即停止当前记录的处理,去处理下一个记录去。
NF != 4 {
printf("%s:%d: skipped: NF != 4\n", FILENAME, FNR) > "/dev/stderr"
next
}
7.4.1 nextfile¶
这个和next类似。 只不过next是去处理下一个记录。 nextfile是出去下一个文件。
7.4.1 exit¶
这个语句设定退出码的。
样例:
BEGIN {
if (("date" | getline date_now) <= 0) {
print "Can't get system date" > "/dev/stderr"
exit 1
}
print "current date is", date_now
close("date")
}
7.5 预定义的变量¶
7.5.1 内建控制变量¶
FIELDWIDTHS 各个字段的宽度
FPAT 各个字段的模式
FS 字段分隔符
IGNORECASE 是否忽略大小写,默认是是大小写敏感的
OFS 输出字段分隔符
ORS 输出记录分隔符
RS 记录分隔符,默认是行,就是一行几个记录
7.5.2 内建传递变量¶
ARGV 命令行参数
ARGC 命令行参数个数
ERRNO 错误号
FILENAME 当前的文件名
FNR 当前的文件记录号
NF 当前记录的字段个数
NR 当前记录数
PROCINFO 这个是一个数组,存储一些进程信息。
7.5.3 使用ARGC和ARGV¶
样例:
[root@centos74 test]$ awk 'BEGIN {
for ( i=0; i<ARGC;i++)
print ARGV[i]
}' inventory-shipped mail-list
awk
inventory-shipped
mail-list
Attention
我们的语句不是参数。第一个参数是awk命令本身的。
8 数组¶
8.1 数组的基本概念¶
简单的说数组就是一组数据的集合而已。使用起来比多个变量更方便,更快捷。
Attention
awk中的数组是引用数组。 可以理解为其他语句的字典吧。
8.1.1 引用数组元素¶
引用数组元素需要写对应的索引的。如下:
[root@centos74 test]$ awk 'BEGIN{a["d1"]="d1"; a["d2"]="d2" ; print a["d1"]}'
d1
判定一个索引是否存在
[root@centos74 test]$ awk 'BEGIN{a["d1"]="d1"; a["d2"]="d2" ; print "d1" in a, "d3" in a }'
1 0
8.1.3 数组的基本使用¶
样例:
{
if ($1 > max)
max = $1
arr[$1] = $0
}
END {
for (x = 1; x <= max; x++)
print arr[x]
}
8.1.4 数组的遍历¶
样例:
BEGIN {
a["here"] = "here"
a["is"] = "is"
a["a"] = "a"
a["loop"] = "loop"
for (i in a) {
j++
a[j] = j
print i
}
}
8.1.4 数组的遍历扩展¶
默认数组的遍历是没有排序的,也就是先设置的先遍历。
内置的一些排序方法如下:
@unsorted 默认的
@ind_str_asc 索引字符串升序
@ind_num_asc 索引数字升序
@val_type_asc 值类型升序
@val_str_asc 值str升序
@val_num_asc 值数字升序
@ind_str_desc 索引字符串降序
@ind_num_desc 索引数字降序
@val_type_desc 值类型降序
@val_str_desc 值字符串降序
@val_num_desc 值数字降序
样例:
$ gawk '
> BEGIN {
> a[4] = 4
> a[3] = 3
> for (i in a)
> print i, a[i]
> }'
-| 4 4
-| 3 3
$ gawk '
> BEGIN {
> PROCINFO["sorted_in"] = "@ind_str_asc"
> a[4] = 4
> a[3] = 3
> for (i in a)
> print i, a[i]
> }'
-| 3 3
-| 4 4
8.3 多维数组¶
8.4 数组中数组¶
这个是比较好理解的。 数组的元素还是一个数组。
具体样例如下:
arrar[1][1]=11
array[1]2]=12
array[2][1]=21
array[2][2]=22
for (i in array)
for (j in array[i])
print array[i][j]
9 函数¶
9.1 内建函数¶
9.1.2 字符串函数¶
asort(source [, dest [, how ] ] 和asorti(source [, dest [, how ]
样例:
a["last"] = "de"
a["first"] = "sac"
a["middle"] = "cul"
# asort(a)a的结果会如下
a[1] = "cul"
a[2] = "de"
a[3] = "sac"
# asorti(a)的结果会如下
a[1] = "first"
a[2] = "last"
a[3] = "middle"
# 一个是根据值生成的,一个是根据索引生成的。
gsub(regexp, replacement [, target])
样例:
[root@centos74 test]$ echo "abcabc" |awk '{gsub(/a/,"A");print $0}'
AbcAbc
index(in, find)
样例:
[root@centos74 test]$ awk 'BEGIN { print index("peanut", "an") }'
3
length([string])
[root@centos74 test]$ awk 'BEGIN { a="abcd" ; print length(a) }'
4
split(string, array [, fieldsep [, seps ] ])
split("cul-de-sac", a, "-", seps)
#得到的结果如下
a[1] = "cul"
a[2] = "de"
a[3] = "sac"
strtonum(str)
[root@centos74 test]$ awk 'BEGIN { a="11" ; print strtonum(a) }'
11
sub(regexp, replacement [, target])
这个和gsub差不多。 只是这个只替换一次。gsub替换所有。
[root@centos74 test]$ echo "abcabc" |awk '{sub(/a/,"A");print $0}'
Abcabc
substr(string, start [, length ])
这个就是提取字字符串的。
[root@centos74 test]$ awk -v a="abcdef" 'BEGIN{b =substr(a,2,2) ; print b}'
bc
tolower(string)和toupper(string)
这个就是转化大小写的
9.1.3 输入输出函数¶
close(filename [, how])
关闭文件
fflush([filename])
把缓冲区的输出写入文件去
system(command)
执行系统命令
样例:
END {
system("date | mail -s 'awk run done' root")
}
9.1.3 时间函数¶
strftime([format [, timestamp [, utc-flag] ] ])
这个方法和python的date类的方法相似
格式也是比较多。具体参考 gawk.
systime()
获取当前时间
9.1.4 位操作¶
and(v1, v2 [, …])
compl(val)
lshift(val, count)
or(v1, v2 [, …])
rshift(val, count)
xor(v1, v2 [, …])
- 1 简介
- awk的简介
- 2 运行awk
- 运行awk
- 3 正则表达式
- 正则表达式
- 4 读取输入文件
- 读取输入文件
- 5 打印输出
- 打印输出
- 6 表达式
- 表达式
- 7 模式动作和变量
- 模式动作和变量
- 8 数组
- 数组
- 9 函数
- 函数