Grep Sed Awk

grep、sed和awk都是文本处理工具,虽然都是文本处理工具单却都有各自的优缺点,一种文本处理命令是不能被另外一个彻底替换的,不然也不会出现三个文本处理命令了。只不过,相比较而言,sed和awk功能更强大而已,且已独立成一种语言来介绍。mysql

grep:文本过滤器,若是仅仅是过滤文本,可以使用grep,其效率要比其余的高不少;
sed:Stream EDitor,流编辑器,默认只处理模式空间,不处理原数据,若是你处理的数据是针对行进行处理的,可使用sed;

awk:报告生成器,格式化之后显示。若是对处理的数据须要生成报告之类的信息,或者你处理的数据是按列进行处理的,最好使用awk。linux

 

grep
grep 是一个最初用于Unix操做系统的命令行工具。在给出文件列表或标准输入后,grep会对匹配一个或多个正则表达式的文本进行搜索,并只输出匹配(或者不匹配)的行或文本。Unix的grep家族包括grep、egrep和fgrep
egrep和fgrep的命令只跟grep有很小不一样。egrep是grep的扩展,支持更多的re元字符fgrep就是fixed grep或fast grep,它们把全部的字母都看做单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,再也不特殊。linux使用GNU版本的grep。它功能更强,能够经过-E、-F命令行选项来使用egrep和fgrep的功能。
grep的工做方式是这样的,它在一个或多个文件中搜索字符串模板。若是模板包括空格,则必须被引用,模板后的全部字符串被看做文件名。搜索的结果被送到屏幕,不影响原文件内容。
grep可用于shell脚本,由于grep经过返回一个状态值来讲明搜索的状态,若是模板搜索成功,则返回0,若是搜索不成功,则返回1,若是搜索的文件不存在,则返回2。咱们利用这些返回值就可进行一些自动化的文本处理工做。

grep:根据模式搜索文本,并将符合模式的文本行显示出来。    
Pattern:文本字符和正则表达式的元字符组合而成匹配条件

使用格式:
grep [options] PATTERN [FILE...]
    -i:忽略大小写    
    --color:匹配到字符用其余颜色显示出来,默认是红色
    -v:显示没有被模式匹配到的行
    -o:只显示被模式匹配到的字符串,不显示行
    -E:使用扩展正则表达式
    -A n:表示显示该行及其后n行
    -B n:表示显示该行及其前n行
    -C n:表示显示该行及其先后各n行
正则表达式:REGular EXPression,REGEXP
元字符:
.:匹配任意单个字符
[]:匹配指定范围内的任意单个字符
[^]:匹配指定范围外的任意单个字符
   字符集和:[:digit:],[:lower:],[:upper:],[:punct:],[:space:],[:alpha:],[:alnum:]
    对应上边:数字  ,小写字母,大写字母,标点符号,空白字符,全部字母,全部数字和字母

匹配次数(贪婪模式,即尽量长的匹配):
*:匹配其前面的字符任意次
   如:编辑文件abc,输入这些字符:a,b,ab,aab,acb,adb,amnb,使用grep匹配a*b,命令及显示效果以下所示:
从 上图能够看到,虽然像acb、adb之类的字符串也能够显示出来,但从显示的颜色能够看到,匹配的仅仅是字符b,虽然整个字符串中也有字符a,可是此时a 并无与b一块儿紧挨着出现,因此仅匹配到字符b;而像ab、aab等字符串,所有显示,此时a紧挨着b出现,符合条件,因此能够显示。

.*:任意长度的任意字符
    如:匹配.b和.*b,看两者有什么区别,命令和显示效果以下:

 

\?:匹配其前面的字符1次或0次nginx

    如:继续上边的例子,如今匹配a\?b,显示效果以下所示:

 

\{m,n\}:匹配其前面的字符至少m次,至多n次git

   \{1,\}:至少一次
   \{0,3\}:最多三次

位置锚定:
^:锚定行首,此字符后面的任意内容必须出如今行首    
$:锚定行尾,此字符前面的任意内容必须出如今行尾
^$:空白行
\<或\b:锚定词首,其后面的任意字符必须做为单词首部出现
\>或\b:锚定词尾,其后边的任意字符必须做为单词尾部出现

    如:\<root\>:在整个文件中,把root做为整个单词出现,词首词尾都不行,如:mroot、rooter均将不匹配
举几个例子来讲明下上边的位置锚定。

 

分组:web

\(\)
   如: \(ab\)*:ab总体做为匹配字符,且匹配任意次
          \(ab\)\{1,\}:ab总体做为匹配字符,且匹配至少一次
          \(ab\):ab总体做为匹配字符

    后向引用
    \1:匹配第一个左括号以及与之对应的右括号所包括的全部内容
    \2:匹配第二个左括号以及与之对应的右括号所包括的全部内容
    \3:匹配第三个左括号以及与之对应的右括号所包括的全部内容
    ......
    如:
新建文件test1,添加内容以下:
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vim test1     #编辑该文件添加以下内容:
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.
[root@www ~] # grep '\(l..e\).*\1' test1    #匹配前边第一个左括号的以及与之对应的右括号的内容
He love his lover.
She like her liker.
[root@www ~] # grep 'l..e' test1          #匹配指定的字符,中间可为任意两个字符
He love his lover.
She like her liker.
He love his liker.
She like her lover.
He like her.
She love he.

 

grep练习:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
一、显示 /proc/meminfo 文件中以不区分大小的s开头的行;
      grep -i '^s' /proc/meminfo    或者
      grep '^[sS]' /proc/meminfo   #[]表示匹配指定范围内的单个字符,所以也可实现不区分大小写
二、显示 /etc/passwd 中以nologin结尾的行;
      grep 'nologin$' /etc/passwd
      扩展一:取出默认shell为 /sbin/nologin 的用户列表
            grep '/sbin/nologin' /etc/passwd | cut -d: -f1    或者
            grep '/sbin/nologin' /etc/passwd | awk -F: '{print $1}'     或者直接使用 awk
            awk -F: '$7 ~ /nologin/{print $1}' /etc/passwd
      扩展二:取出默认shell为 bash ,且其用户ID号最小的用户的用户名
            grep 'bash$' /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1   或者
            awk -F: '$7 ~ /bash/{print $3,$1}' /etc/passwd | sort -n | head -1 | awk '{print $2}'
三、显示 /etc/inittab 中以 #开头,且后面跟一个或多个空白字符,然后又跟了任意非空白字符的行;
       grep '^#[[:space:]]\{1,\}[^[:space:]]' /etc/inittab
四、显示 /etc/inittab 中包含了:一个数字:(即两个冒号中间一个数字)的行;
       grep ':[0-9]:' /etc/inittab
五、显示 /boot/grub/grub .conf文件中以一个或多个空白字符开头的行;
       grep '^[[:space:]]\{1,\}' /boot/grub/grub .conf
六、显示 /etc/inittab 文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;
       grep '\(^[0-9]\).*\1$' /etc/inittab     #在RHEL5.8之前的版本中可查看到效果
七、找出某文件中的,1位数,或2位数;
       grep '\<[[:digit:]][[:digit:]]\?\>' /etc/inittab  或者
       grep '\<[0-9]\{1,2\}\>' /etc/inittab
八、查找当前系统上名字为student(必须出如今行首)的用户的账号的相关信息, 文件为 /etc/passwd
       grep '^student:' /etc/passwd
       扩展:若存在该用户,找出该用户的ID号:
             grep '^student:' /etc/passwd | cut -d: -f3  或者 # id -u student
思考题:用多种方法找出本地的IP地址,这里给出三种方法,若是你还有其余方法能够一块儿分享下:
1
2
3
ifconfig eth0| grep -oE '([0-9]{1,3}\.?){4}' | head -n 1
ifconfig eth0| awk -F: '/inet addr/{split($2,a," ");print a[1];exit}'     #这里使用了awk的内置函数,若是不懂可在看完awk的介绍后再来作此题
ifconfig | grep "inet addr" | grep - v "127.0.0.1" | awk -F: '{print $2}' | awk '{print $1}'

 

sed
sed(意为流编辑器,源自英语stream editor”的缩写)是Unix常见的命令行程序。sed 用来把文档或字符串里面的文字通过一系列编辑命令转换为另外一种格式输出。sed 一般用来匹配一个或多个正则表达式的文本进行处理。sed是一种在线编辑器, 它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并无 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操做;编写转换程序等。

使用格式:    
sed 'AddressCommand' file ...
    -n:静默模式,再也不显示模式空间中的内容
    -i:直接修改原文件
    -e SCRIPT -e SCRIPT:添加脚本到将要执行的命令中,能够同时执行多个脚本
    -f /PATH/TO/SED_SCORIPT:添加脚本文件中的内容到将要执行的命令中
         #sed -f /path/to/script file
    -r:表示使用扩展正则表达式

Address:
一、StartLine,EndLine:开始行,结束行
   如:1,100:表示从第1行到第100行
    $;最后一行
二、/RegExp/:扩展正则表达式
   如:/^root/
三、/pattern1/,/pattern2/:表示第一次被pattern1匹配到的行开始,至第一次被pattern2匹配到的行结束,这中间的全部行
四、LIneNumber:指定的行
五、StartLIne,+N:从StartLine开始,向后的N行

Command:
    d:删除符合条件的行;
    p:显示符合条件的行,在不使用-n选项时被匹配到的行会显示两遍,由于sed处理时会把处理的信息输出
    a \string:在指定的行后面追加新行,内容为“string”,
        显示两行或多行,在每行后加\n进行换行
    i \string:在指定的行前面添加新行,内容为string
    r file:将指定的文件的内容添加至符合条件的文件中
    w file:将地址指定范围内的行另存至指定的文件中
    s/pattern/string/修饰符:查找并替换,默认只替换每行中第一次被模式匹配到的字符串
        加修饰符
         g:全局替换,如:s/pattern/string/g
         i:忽略字符大小写,如:s/pattern/string/i
    s///,s###,s@@@均可以,当所使用的分割符号与内容中显示的相同时,需使用转义字符转义    
        \(\),\1,\2:成组匹配,\1表示匹配第一个‘(’,\2表示匹配第二个‘(’
    &:引用模式匹配到的整个串
介绍了那么多,如今从咱们的系统中复制个文件,做为咱们的测试文件,这里,咱们复制/etc/inittab文件,并稍加修改,删掉几行,而后做为测试文件使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cp /etc/inittab ./    #复制该文件到当前目录下,这里当前处于root家目录下。
vim inittab     #编辑该文件,修改此文件,内容以下所示,其内容也可参看下边的图片
# inittab is only used by upstart for the default runlevel.
#
           #此处是一空行,没有任何字符,就光空行添加代码时会被删掉,因此这里加上备注,说明是一空交行,下面相同
# Individual runlevels are started by /etc/init/rc.conf
#
            #此处是一空行,没有任何字符。该文件内容也看参见下边的图片
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:

 

 

用复制并修过的inittab文件做为测试文件,举几个例子:面试

1
[root@www ~] # sed '1,3d' inittab:表示删除文件的第一到第三行

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[root@www ~] # sed '3,$d' inittab   #表示删除模式空间中的第三到最后一行
# inittab is only used by upstart for the default runlevel.
#
[root@www ~] # sed '/run/d' inittab     #表示删除被run匹配到的行
#
#
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed '/^#/d' inittab     #表示删除文件中以#开头的行
id :3:initdefault:
[root@www ~] # sed -n '/^\//p' inittab    #显示以/开头的行,由于没有这样的行,故不显示任何信息
[root@www ~] # sed '/^#/p' inittab        #显示以#开头的行,能够看到被匹配到的行,均显示了两遍,这是由于sed处理时会把处理的信息输出
# inittab is only used by upstart for the default runlevel.
# inittab is only used by upstart for the default runlevel.
#
#
# Individual runlevels are started by /etc/init/rc.conf
# Individual runlevels are started by /etc/init/rc.conf
#
#
# Default runlevel. The runlevels used are:
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   3 - Full multiuser mode
#   4 - unused
#   4 - unused
#   5 - X11
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#   6 - reboot (Do NOT set initdefault to this)
#
#
id :3:initdefault:
[root@www ~] # sed -n '/^#/p' inittab     #显示以#开头的行,使用-n选项表示仅显示匹配到的行
# inittab is only used by upstart for the default runlevel.
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#

 

为了后边的演示,建立文件test,添加以下内容:
Welcome to my linux!
This is my world.
How are you?

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
vim test    #编辑该文件添加以下内容:
Welcome to my linux!
This is my world.
How are you?
[root@www ~] # sed '2r ./test' inittab    #表示将test文件中的内容添加到inittab文件中,且从第二行日后开始添加
# inittab is only used by upstart for the default runlevel.
#
Welcome to my linux!              #新添加的三行内容
This is my world.
How are you?
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed '1,2r ./test' inittab    #表示将test文件中的内容添加到inittab文件中,且分别 添加在第一和第二行后边
# inittab is only used by upstart for the default runlevel.
Welcome to my linux!              #新添加的三行内容
This is my world.
How are you?
#
Welcome to my linux!                    #新添加的三行内容
This is my world.
How are you?
# Individual runlevels are started by /etc/init/rc.conf
#
# Default runlevel. The runlevels used are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id :3:initdefault:
[root@www ~] # sed 's/linux/LINUX/g' test     #查找该文件中的字符串,而后替换为指定的字符串
Welcome to my LINUX!                #能够看到以替换为大写的linux
This is my world.
How are you?
[root@www ~] # sed 's/y.u/&r/g' test    #查找指定的字符串,并将其替换为在其后加上r,分隔符采用/
Welcome to my linux!
This is my world.
How are your?
[root@www ~] # sed 's@y.u@&r@g' test     #意义同上,分隔符采用@
Welcome to my linux!
This is my world.
How are your?
[root@www ~] # sed 's#y.u#&r#g' test      #意义同上,分隔符采用#
Welcome to my linux!
This is my world.
How are your?

 

sed练习;正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
一、删除 /etc/grub .conf文件中行首的空白符;
       sed  -r 's/^[[:space:]]+//' /etc/grub .conf
二、替换 /etc/inittab 文件中“ id :3:initdefault:”一行中的数字为5;
      sed 's/\(id:\)[0-9]\(:initdefault:\)/\15\2/g' /etc/inittab
三、删除 /etc/inittab 文件中的空白行;
      sed '/^$/d' /etc/inittab
四、删除 /etc/inittab 文件中开头的 #号;
      sed 's/^#//g' /etc/inittab
五、删除某文件中开头的 #号及其后面的空白字符,但要求#号后面必须有空白符;
      sed 's/^#[[:space:]]\{1,\}//g' /etc/inittab     或者
      sed  -r 's/^#[[:space:]]+//g' /etc/inittab
六、删除某文件中以空白字符后面跟 #类的行中的开头的空白字符及#
      sed -r 's/^[[:space:]]+#//g' /etc/inittab
七、取出一个文件路径的目录名称;
      echo "/etc/rc.d/abc/edu/" | sed -r 's@^(/.*/)[^/]+/?@\1@g'        #因sed支持扩展正则表达式,在扩展正则表达式中,+表示匹配其前面的字符至少1次
八、取出一个文件路径的最后一个文件名;
      echo "/etc/rc.d/abc/edu/" | sed -r 's@^/.*/([^/]+)/?@\1@g'

awk

awk是一种优良的文本处理工具,LinuxUnix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操做语言(其名称得自于它的创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一我的所拥有的知识。AWK提供了极其强大的功能:能够进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具有了一个完整的语言所应具备的几乎全部精美特性。实际上AWK的确拥有本身的语言:AWK程序设计语言,三位建立者已将它正式定义为“样式扫描和处理语言”。它容许您建立简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其余的功能。最简单地说,AWK是一种用于处理文本的编程语言工具。咱们如今使用最多的是gawk,gawk是AWK的GNU版本。
sql

使用格式:
# awk [options] 'script' file1, file2, ...
# awk [options] 'PATTERN { action }' file1, file2, ...

awk的输出:print和printf
1、print
print的使用格式:
    print item1, item2, ...
要点:
一、各项目之间使用逗号隔开,而输出时则以空白字符分隔;
二、输出的item能够为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,然后再输出;
三、print命令后面的item能够省略,此时其功能至关于print $0, 所以,若是想输出空白行,则须要使用print "";

例子:
1
2
awk 'BEGIN { print "line one\nline two\nline three" }'
awk -F: '{ print $1, $7 }' /etc/passwd     #等价于:awk -v FS=: '{print $1,$7}' /etc/passwd

 

2、awk变量shell

2.1 awk内置变量之记录变量:
FS: field separator,字段分隔符,默认是空白字符;
RS: Record separator,记录分隔符,默认是换行符;
OFS: Output Filed Separator,输出字段分隔符
ORS:Output Row Separator,输出行分隔符

一块儿来看一个示例:express

 

1
2
3
4
5
vim test .txt   #编辑该文件,添加以下两行信息做为示例使用
welcome to redhat linux.
how are you?
[root@www ~] # awk 'BEGIN{OFS="#"} {print $1,$2}' test.txt    #指定输出时的分隔符
[root@www ~] # awk 'BEGIN{OFS="#"} {print $1,"hello",$2}' test.txt   #指定输出时的分隔符,并添加显示的内容
上边两个命令的显示效果以下所示:

1
2
3
4
5
6
7
8
9
[root@www ~] # awk -v FS=:  -v OFS=# '{print $1,$7}' /etc/passwd    #以:为字段分隔符,以#号为输出分隔符,显示该文件的第一及第七字段的值,这里仅贴出部分显示内容
root #/bin/bash
bin #/sbin/nologin
daemon #/sbin/nologin
adm #/sbin/nologin
lp #/sbin/nologin
sync #/bin/sync
shutdown #/sbin/shutdown
halt #/sbin/halt
2.2 awk内置变量之数据变量:
NR: The number of input records,awk命令所处理的记录数;若是有多个文件,这个数目会把处理的多个文件中行统一计数;
NF:Number of Field,当前记录的字段个数,有时可用来表示最后一个字段
FNR: 与NR不一样的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数;
ARGV: 数组,保存命令行自己这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt;
ARGC: awk命令的参数的个数;
FILENAME: awk命令所处理的文件的名称;
ENVIRON:当前shell环境变量及其值的关联数组;
如:
1
2
awk 'BEGIN{print ENVIRON["PATH"]}'
awk '{print $NF}' test .txt

2.3 用户自定义变量
gawk容许用户自定义本身的变量以便在程序代码中使用,变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。

2.3.1 在脚本中赋值变量
在gawk中给变量赋值使用赋值语句进行,例如:
1
2
[root@www ~] # awk 'BEGIN{var="variable testing";print var}'   #给变量赋值,并输出变量的值,下边是显示效果
variable testing

2.3.2 在命令行中使用赋值变量
gawk命令也能够在“脚本”外为变量赋值,并在脚本中进行引用。例如,上述的例子还能够改写为:
1
2
[root@www ~] # awk -v var="variable testing" 'BEGIN{print var}'     #与上述的例子同样,显示效果以下
variable testing

3、printf
printf命令的使用格式:
printf format, item1, item2, ...
要点:
一、其与print命令的最大不一样是,printf须要指定格式;
二、format用于指定后面的每一个item的输出格式;
三、printf语句不会自动打印换行,须要显式使用\n换行。

format格式的指示符都以%开头,后跟一个字符;以下:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;

修饰符:
N: 显示宽度;
-: 左对齐;
+:显示数值符号;
例子:
1
awk -F: '{printf "%-15s%i\n",$1,$3}' /etc/passwd      #使用printf显示该文件中的第一列和第三列,要求第一列左对齐且占用15个字符宽度,第二列显示十进制整数,显示效果以下所示:

 

4、输出重定向

使用格式:
print items > output-file
print items >> output-file
print items | command
特殊文件描述符:
/dev/stdin:标准输入
/dev/sdtout: 标准输出
/dev/stderr: 错误输出
/dev/fd/N: 某特定文件描述符,如/dev/stdin就至关于/dev/fd/0;
例子:
1
awk -F: '{printf "%-15s %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd    #显示效果与上述例子同样,只不过这里是重定向到错误输出,而后显示

6、awk的操做符:
6.1 算术操做符:
-x:负值
+x:转换为数值;
x^y:x的y次方
x**y: x的y次方
x*y:乘法
x/y:除法
x+y:加法
x-y:减法
x%y:取余

6.2 字符串操做符:
只有一个,并且不用写出来,用于实现字符串链接;
1
2
[root@www ~] # awk 'BEGIN{print "A" "B"}'     #链接A和B两个字符,使其成为一个字符串,显示效果以下所示:
AB

6.3 赋值操做符:
=
+=
-=
*=
/=
%=
^=
**=
++
--

须要注意的是,若是某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代;

6.4 布尔值
awk中,任何非0值或非空字符串都为真,反之就为假;

6.5 比较操做符:
x < y     True if x is less than y.
x <= y     True if x is less than or equal to y.
x > y     True if x is greater than y.
x >= y     True if x is greater than or equal to y.
x == y     True if x is equal to y.
x != y     True if x is not equal to y.
x ~ y     True if the string x matches the regexp denoted by y. 若是字符串x被y表示的正则表达式匹配,则为真;
x !~ y     True if the string x does not match the regexp denoted by y. 若是字符串x不被y表示的正则表达式匹配,则为真;
subscript in array       True if the array array has an element with the subscript subscript.

如:
1
2
3
[root@www ~] # awk -F: '$1 ~ /^root/{print $1,$3,$4,$NF}' /etc/passwd    #显示该文件中以root开头的行的第一列、第三列、第四列和最后一列,显示效果以下所示:
root 0 0 /bin/bash
[root@www ~] # awk -F: '$3>=400{printf "%-15s%-10i%s\n",$1,$3,$NF}' /etc/passwd #显示UID大于400的行的第一列、第三列和最后一列

6.7 表达式间的逻辑关系符:
&&
||

6.8 条件表达式:
selector?if-true-exp:if-false-exp

6.9 函数调用:
function_name (para1,para2)

七 awk的模式:
awk 'program' input-file1 input-file2 ...
其中的program为:
pattern { action }
pattern { action }
...

7.1 常见的pattern类型:
一、Regexp: 正则表达式,格式为/regular expression/
    如:
1
2
3
4
5
[root@www ~] # awk -F: '/bash/{print $0}' /etc/passwd    #在/etc/passwd中查找有bash的行,并显示
root:x:0:0:root: /root : /bin/bash
nginx:x:496:493:: /home/nginx : /bin/bash
mysql:x:495:492:: /home/mysql : /bin/bash
wpuser:x:494:491:: /home/wpuser : /bin/bash

二、expresssion: 表达式,其值非0或为非空字符时知足条件,如:$1 ~ /foo/ 或 $1 == "lq2419",用运算符~(匹配)和~!(不匹配)。
    如:
1
2
3
awk -F: '$3>=500{printf "%-15s%s\n",$1,$3}' /etc/passwd
awk -F: '$1 ~ /root/{print $1,$3}' /etc/passwd
      等价于: awk -F: '$1=="root"{print $1,$3}' /etc/passwd

三、Ranges: 指定的匹配范围,格式为pat1,pat2

四、BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次
    如:
1
2
3
4
5
6
7
8
9
[root@www ~] # awk -F: 'BEGIN{print "Username       UID"}$3>=400{printf "%-15s%s\n",$1,$3}' /etc/passwd       #上式表示对于该文件,在开始比较前先输出username和UID做为题头,而后,输出UID大于400的行的第一列和第三列
Username       UID
rtkit          499
pulse          498
saslauth       497
nfsnobody      65534
nginx          496
mysql          495
wpuser         494
如今我想输出/etc/passwd文件中的第一列,那么,有多少种方法能够实现呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
有三中方式都可以实现,命令及显示效果以下:
[root@www ~] #  awk -v FS=: '{print $1}' /etc/passwd    #使用-v选项和FS指定分隔符,而后显示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
[root@www ~] # awk -F: '{print $1}' /etc/passwd       #直接使用-F选项指定分隔符,而后显示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
[root@www ~] # awk 'BEGIN{FS=":"}{print $1}' /etc/passwd    #使用BEGIN,在运行前指定分隔符,而后显示
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp

五、Empty(空模式):匹配任意输入行;

7.2 常见的Action
一、Expressions:
二、Control statements
三、Compound statements
四、Input statements
五、Output statements


/正则表达式/:使用通配符的扩展集。
关系表达式:能够用下面运算符表中的关系运算符进行操做,能够是字符串或数字的比较,如$2>$1选择第二个字段比第一个字段长的行。

模式匹配表达式:
模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
BEGIN:让用户指定在第一条输入记录被处理以前所发生的动做,一般可在这里设置全局变量。
END:让用户在最后一条输入记录被读取以后发生的动做。

八 控制语句:
8.1 if-else
语法:if (condition) {then-body} else {[ else-body ]}
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@www ~] # awk -F: '{if ($1=="root") print $1, "Admin"; else print $1, "Common User"}' /etc/passwd    #判断若是第一个字段是root,则显示是admin,不然显示是common user,显示结果以下所示:
root Admin
bin Common User
daemon Common User
adm Common User
lp Common User
sync Common User
shutdown Common User
halt Common User
[root@www ~] # awk -F: '{if ($1=="root") printf "%-15s%s\n", $1,"Admin"; else printf "%-15s%s\n", $1, "Common User"}' /etc/passwd          #显示效果同上,只不过这里使用printf,显示定义显示的格式
root             Admin
bin              Common User
daemon           Common User
adm              Common User
lp               Common User
sync             Common User
shutdown         Common User
halt             Common User
mail             Common User
uucp             Common User
[root@www ~] # awk -F: -v sum=0 '{if ($3>=400) sum++}{if ($3>=400) printf "%-15s%i\n",$1,$3}END{print "Sum = "sum;}' /etc/passwd                #定义变量sum=0,而后判断若是UID大于400,让sum自加,而且若是UID大于等于400的显示其用户名和UID,结束前输出sum的值
rtkit             499
pulse             498
saslauth          497
nfsnobody         65534
nginx             496
mysql             495
wpuser            494
Sum = 7

8.2 while
语法: while (condition){statement1; statment2; ...}
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@www ~] # awk -F: -v i=1 '{while (i<=7) {print $i;i++}}' /etc/passwd    #使用-v选项显示定义变量i=1,当i小于等于7时循环结束,而后,输出第一个字段到第七个字段,当i为7时,正好输出的是第一行的7个字段的值
root
x
0
0
root
/root
/bin/bash
[root@www ~] # awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd    #定义变量i,先判断,当i小于等于3时,输出第一到第三个字段的值,所处理的数据时该文件中的每一行数据,而不只仅是第一行。这里须要注意与上述命令的 区别
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

8.3 do-while
语法: do {statement1, statement2, ...} while (condition)
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@www ~] # awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd    #意义同上,显示效果虽与上述相同,但与while不一样的是,do-while是先执行一趟,而后再判断是否知足条件,也就是说无论条件是否知足,都会先 执行一趟;而while中若是条件不知足,则一趟也不会执行
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

8.4 for
语法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@www ~] # awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd     #使用for循环,输出各行的前三个字段
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4

for循环还能够用来遍历数组元素:
语法: for (i in array) {statement1, statement2, ...}
1
2
3
4
5
6
[root@www ~] # awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd      #匹配最后一个字段不空的行,把最后一段当作数组下标,输出各下标的值,及各下标对应的个数,各下标的个数保存在数组中
          /bin/sync :1
          /bin/bash :4
      /sbin/nologin :29
         /sbin/halt :1
     /sbin/shutdown :1


8.5 case
语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}

8.6 break 和 continue
经常使用于循环或case语句中

8.7 next
提早结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@www ~] # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd    #UID号对2取余,若是为0,直接处理下一行,不然,输出用户名和UID号,显示效果以下所示:
bin 1
adm 3
sync 5
halt 7
operator 11
gopher 13
nobody 99
dbus 81
usbmuxd 113
vcsa 69
rtkit 499
saslauth 497
postfix 89
abrt 173
rpcuser 29
mysql 495

九 awk中使用数组
9.1 数组
array[index-expression]
index-expression可使用任意字符串;须要注意的是,若是某数据组元素事先不存在,那么在引用其时,awk会自动建立此元素并初始化为空串;所以,要判断某数据组中是否存在某元素,须要使用index in array的方式。

要遍历数组中的每个元素,须要使用以下的特殊结构:
for (var in array) { statement1, ... }
其中,var用于引用数组下标,而不是元素值;
例子:
1
2
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值作为数组S的元素索引
1
2
3
4
5
6
7
8
9
10
11
[root@www ~] # awk '{IP[$1]++}END{for (A in IP) printf "%-20s%s\n",A,IP[A]}' /var/log/nginx/access.log     #用法与上一个例子相同,用于统计某日志文件中IP地的访问量
172.16.32.30         3
172.16.32.50         31596
172.16.32.52         408
192.168.0.239        1886
172.16.32.0          1010
[root@www ~] # awk 'BEGIN{A["m"]="hello";A["n"]="world";print A["m"],A["n"]}'     #开始前对数组赋值,而后输出数组的值
hello world
[root@www ~] # awk 'BEGIN{A["m"]="hello";A["n"]="world";for (B in A) print A[B]}'      #在开始前对数组赋值,而后使用for循环,把B当作下标,依次输出数组中的值
hello
world

9.2 删除数组变量
从关系数组中删除数组索引须要使用delete命令。使用格式为:
delete  array[index]

10、awk的内置函数
split(string, array [, fieldsep [, seps ] ])
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列;
1
netstat -ant | awk '/:22\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50  #显示效果以下所示:
length([string])
功能:返回string字符串中字符的个数;
substr(string, start [, length])
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;
system(command)
功能:执行系统command并将结果返回至awk命令
systime()
功能:取系统当前时间
tolower(s)
功能:将s中的全部字母转为小写
toupper(s)
功能:将s中的全部字母转为大写

11、用户自定义函数
自定义函数使用function关键字。格式以下:
function F_NAME([variable])
{
    statements
}

函数还可使用return语句返回值,格式为“return value”。


在 最后,介绍个面试中常被问到的关于awk的一个问题,顺便给出几个好玩的awk命令。有时候面试的时候,会被问到,使用awk编写脚本打印出乘法口诀,牛 人固然以为这小菜一碟,可是,像咱们这些菜鸟,可就该抓耳挠腮了,本人通过上网搜索,加上本身尝试,写出了该脚本。先附上脚本及打印效果,以供参考。
一、乘法口诀
1
2
3
4
5
6
7
8
9
10
11
12
vim cfkj.sh   #编辑该文件,输入以下内容:
#!/bin/awk -f
BEGIN{
         for (i=1;i<=9;i++)
         {
         for (m=1;m<=i;m++)
                 {
                         printf m "*" i "=" m*i "  "
                 }
         print
         }
}

 

二、打印图案

接 触过C语言的都知道,咱们在刚开始学C语言的时候,有时候为了让你可以学下去,特别是在谭浩强版的C程序设计丛书中,会有不少课后习题,让你用C语言实现 打印一些图案等,甚至是一些有意思的像编程实现使各行、各列以及对角线之和都相等之类的图标等等。那若是如今让你用awk来实现,打印一个图案,又该如何 实现呢?比方说,使用awk打印以下图案。
         *
        ***
      *****
     *******
对于这个咱们又该如何实现呢?其实,可以使用以下命令实现打印此图案。
1
awk 'BEGIN {for(i=1;i<=4;i++) {for(j=1;j<=10-i;j++) {printf " ";}for(j=1;j<=(2*i-1);j++) {printf "*";}printf "\n";}}'

三、使用数字打印中心对称图形
这个就有点难度了。本人也没有想出来,这个是一个朋友给个人,以为好玩,就拿出来跟你们分享一下。这里直接给出命令及显示效果了,就不吊各位胃口了。
1
2
echo 15| awk '{x=8; for (i=1;i<$0;i++){ for (j=1;j<=3*($0-i)-(x>0?x:0);j++) printf " " ; for (k=i;k>=1;k--) printf "%d " ,k; for (l=2;l<=i;l++) printf "%d " ,l; printf "\n" ;x--};\
for (i=1;i<=$0;i++){ for (j=1;j<=(i<=$0-10+1?3*(i-1):3*(i-1)+2-(i-$0%10-10*int(($0-10) /10 )));j++) printf " " ; for (k=$0-i+1;k>=1;k--) printf "%d " ,k; for (l=2;l<=$0-i+1;l++) printf "%d " ,l; printf "\n" }}'
相关文章
相关标签/搜索