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.2 基础的转义符号

下面这些是c语言的风格的控制符号, bash中的echo,printf都是差不多的。

\\          字符“\”
\\a         响铃
\n          新行
\r          回车
\t          水平制表符TAB

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

4.9 提取数据从getline

4.9.1 使用getline 到一个变量中
{
    if ((getline tmp) > 0) {
        print tmp
        print $0
    } else
        print $0
}
4.9.2 使用getline从一个文件来
{
    if ($1 == 10) {
        getline < "secondary.input"
        print
    } else
        print
}

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.2 比较判定表达式

就是常用大于等于小于这些判定

Note

在字符串比较的时候,是按照首字母比较的,如果相同继续比较下一个字母,而非字母长度比较。

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 if

样例:

if (x % 2 == 0)
    print "x is even"
else
    print "x is odd"
7.4.1 while

样例:

awk '
{
    i = 1
    while (i <= 3) {
        print $i
        i++
    }
}' inventory-shipped
7.4.1 do-while

样例:

{
    i = 1
    do {
        print $0
        i++
    } while (i <= 10)
}
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 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.2 给数组赋值

样例:

arr["key"]=value
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 删除数组

一个一个去删除:

for (i in frequencies)
    delete frequencies[i]

一次清空:

delete frequencies

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.1 调用函数

样例:

i = 4
j = sqrt(i++)
9.1.2 数字函数

函数:

atan2(y,x)
cos(x)
exp(x)
int(x)
log(x)
rand()
sin(x)
sqrt(x)
srand()
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 [, …])

9.1.5 获取类型

isarray(x)

typeof(x)

9.2 用户自定义函数

9.2.1 自定义函数样例
function myprint(num)
{
    printf "%6.3g\n", num
}

定义函数可以在BEGIN里面定义的。 当然写到一个文件也是可以的。

9.2.2 间接函数样例
the_func = "sum"
result = @the_func()   # calls the sum() function
1 简介
awk的简介
2 运行awk
运行awk
3 正则表达式
正则表达式
4 读取输入文件
读取输入文件
5 打印输出
打印输出
6 表达式
表达式
7 模式动作和变量
模式动作和变量
8 数组
数组
9 函数
函数

1 awk库函数

2 awk实用程序

1 awk库函数
awk库函数
2 awk实用程序
awk实用程序