grep

文本过滤(模式:PATTERN)工具(egrep)

  1. [root@localhost ~]# grep --help
  2. Usage: grep [OPTION]... PATTERN [FILE]...
  • PATTERN:模式(可以使用正则表达式)

1.参数部分2.正则部分

常用参数

参数 作用
-v 显示不能被pattern匹配到的行
-i 忽略大小写
-o 仅显示匹配到的字符
-w 全字符匹配
-c 输出匹配到的行数,count
-n 带行号输出
- q 静默匹配,不输出任何信息
-A # after,匹配后#行
-B # before,匹配前#行
-C # context,匹配前后各#行
-E 使用ERE(拓展正则表达式)等同于egrep

参数

#-o,只输出匹配的内容
[root@node01 ~]# cat log.txt | grep -o system 
system
system
system
system

#-H,带文件名输出,-h为不带
[root@node01 ~]# grep system log.txt -H
log.txt:    2 systemctl stop firewalld
log.txt:    3 systemctl disable firewalld
log.txt:   10 systemctl status firewalld
log.txt:   11 systemctl disabled firewalld

#-b,带比特位输出
[root@node01 ~]# grep system log.txt -b
23:    2 systemctl stop firewalld
55:    3 systemctl disable firewalld
393:   10 systemctl status firewalld
427:   11 systemctl disabled firewalld

#-n,带行号输出
[root@node01 ~]# grep system log.txt -n
2:    2 systemctl stop firewalld
3:    3 systemctl disable firewalld
10:   10 systemctl status firewalld
11:   11 systemctl disabled firewalld

# 这个可以带行号输出,比grep好用
[root@node01 ~]# nl test.txt

练习题:

1.显示/proc/meminfo文件中以大小s开头的行(2种方式)
[root@localhost ~]# grep -i '^s' /proc/meminfo
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Shmem:             11916 kB
Slab:             157928 kB
SReclaimable:     104624 kB
SUnreclaim:        53304 kB
[root@localhost ~]# grep  '^[S,s]' /proc/meminfo
SwapCached:            0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Shmem:             11916 kB
Slab:             157928 kB
SReclaimable:     104624 kB
SUnreclaim:        53304 kB

 2.显示/etc/passwd文件中不以/bin/bash结尾的行
[root@localhost ~]# grep -v '/bin/bash$' /etc/passwd 

 3.找出/etc/passwd中的两位或三位数
 [root@localhost ~]# grep -E '\<[0-9]{2,3}\>' /etc/passwd

 4.如果root用户存在,显示其默认的shel1程序/etc/passwd
id root > /dev/null && grep '^root\>' /etc/passwd | awk -F: '{print $7}'
[root@tenor ~]# id root  && grep "^root\>"  /etc/passwd | cut -d: -f7


6.显示/etc/grub2.cfg文件中,至少以一个空白字符开头的且后面存非空白字符行
grep -v  '^ ' /etc/grub2.cfg

7.找出“netstat -tan"命令的结果中以'LISTEN'后跟0、1或多个空白字符结尾的行

8.添加用户bash、testbash以及nologin(其shell为/sbin/nologin),然后找出/etc/passwd文件中用户名同shell名的行

sed

文本编辑器 stream editor

“非交换式”面向字符流的编辑器,能够同时处理多个文件多行的内容,可以不对源文件改动,把整个文件输入到屏幕上,也可以把匹配到的模式的内容输入到屏幕上。还可以对源文件改动,但是不输入到屏幕上。

[root@localhost ~]# sed --help
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
sed的命令格式: sed [option] 'sed command' filename 
sed的脚本格式:sed [option] ‐f 'sed script' filename

{script-only-if-no-other-script} :脚本 -f 指定

sed ‘表达式’ | sed ‘表达式’ == sed ‘表达式’, ‘表达式’

常用参数

参数 作用
-n 只打印模式匹配的行
-e 直接在命令行模式下进行sed编辑,为模式选择
-f 将sed的动作写在一个文件中,-f filename执行filename中sed动作
-r 支持拓展正则表达式
-i 直接修改文件内容

编辑命令

命令 说明
p 打印匹配的行(-n)
P 打印匹配到的第一行
s 替换替换标记:
g:行内全局替换
p:显示替换成功的行
w:将替换成功后的内容保存到指定文件中
n 读取下一个输入行,用下一个命令处理新的行而不是第一个命令
N 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码
d 删除定位行
D 删除模块板的第一行
r filename 读另一文本到本文本中
w filename 写文本到另一个文本中,写并追加模板块到file末尾
W filename 写并追加模板块的第一行到file末尾
a\ 指定行号后添加新文本
i\ 指定行号前添加新文本
c\ 用新文本内容替换定位到的行
q 第一个模式匹配后立即退出
表示后面的命令对所有没有被选定的行发生作用
= 打印当前行号
# 把注释扩展到第一个换行符以前

sed ‘s///g’ 与 sed ‘s///‘
加g:匹配每一行有行首到行尾的所有字符
不加g:匹配每一行的行首开始匹配,匹配到第一个符合的字段,就会结束,跳到下一行
https://blog.51cto.com/luzhi1024/1650729

[root@164-156A164 linshi]# cat 3.txt
hello hello hello
   hello  hello
hello  hello hello

[root@164-156A164 linshi]# sed 's/hello/nihao/' 3.txt  #不指定开头,也不加g,结果是匹配到一个符合的字段就直接跳到下一行
nihao hello hello
   nihao  hello
nihao  hello hello

[root@164-156A164 linshi]# sed 's/hello/nihao/g' 3.txt  ##不指定开头,加g,匹配全部
nihao nihao nihao
   nihao  nihao
nihao  nihao nihao
[root@164-156A164 linshi]# sed 's/^hello/nihao/g' 3.txt #指定开头,加全局g,同上
nihao hello hello
   hello  hello
nihao  hello hello
eg:
1.将/etc/selinux/config中enforcing设置为disabled ,这样可以永久关闭selinux1.1
[root@localhost ~]# cat /etc/selinux/config

sed元字符集

命令 说明
^ 匹配行开始,如:/^sed/匹配所有以sed开头的行。
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
[] 匹配一个指定范围内的字符,如/[sS]ed/匹配sed和Sed。
[^] 匹配一个不在指定范围内的字符,如:/A-RT-Zed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
(..) 匹配子串,保存匹配的字符,如s/(love)able/\1rs,loveable被替换成lovers。
& 保存搜索字符用来替换其他字符,如s/love/&/,love这成love
< 匹配单词的开始,如:/<love/匹配包含以love开头的单词的行。
> 匹配单词的结束,如/love>/匹配包含以love结尾的单词的行。
x{m} 重复字符x,m次,如:/0{5}/匹配包含5个0的行。
x{m,} 重复字符x,至少m次,如:/0{5,}/匹配至少有5个0的行。
x{m,n} 重复字符x,至少m次,不多于n次,如:/0{5,10}/匹配5~10个0的行。

查询文本的方式

参数 意义
x 行号
x,y 从x行到y行
x,y! x行到y行
/PATTREN 查询包含模式的行
/pattern/,/pattern/ 查询包含两个模式的行
/PATTREN/,y y行内查询包含该模式的行
x,/pattern/ x行后查询包含该模式的行

sed练习题测试:

[root@tenor ~]# cat 2.txt
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

查询

1 查询文本的第10,11行
[root@tenor ~]# sed -n '10,11p' 2.txt
Special cases aren't special enough to break the rules.
Although practicality beats purity.

2.#打印从第5行开始到第一个包含以a开始的行之间的所有行
[root@node01 ~]# nl test.txt 
    1 aaa is aaa is aaa isaax
    2 bb aaa ks aaa ks aaa 
    3 asdsdagfjpjadfadfjakldfjk
    4 a
    5 dgsfg
    6 fasggre
    7 wgsgt
    8 wethynyhyjurtj
    9 rhtgf
   10 gsgnhtyehjwyet
   11 ertwsgfn
   12 yjhq3y4twe
   13 sgdfbgsacwerebv
[root@node01 ~]# sed -n '5,/a/p' test.txt   //5~6行,第6行有a
dgsfg
fasggre

替换

#1 将每行的第一个better替换为Elliot,注意三个/,都不能少
[root@node01 ~]# sed 's/better/Elliot/' zen

#2 发现后面加个p会重复打印匹配到的行
[root@node01 ~]# sed 's/better/Elliot/p' zen

#3 前面加个n就会只打印匹配到的行
[root@node01 ~]# sed -n 's/better/Elliot/p' zen

#4 从第N处开始替换,可以使用Ng
[root@node01 ~]# cat test.txt 
aaa is aaa is aaa isaax
bb aaa ks aaa ks aaa 
#把从第二个开始包括第二个的aaa替换
[root@node01 ~]# sed 's/aaa/-------------/2g' test.txt 
aaa is ------------- is ------------- isaax
bb aaa ks ------------- ks ------------- 


# 将所有的都替换
---总结:
n+p : 替换后,只打印匹配到的行,如果此时-i,那么保存到文件中的也只有匹配的行
p   : 替换后,匹配到的行打印两边
null: 替换后,打印全文
+g : 全局替换,如果不加,只会替换每一行的第一个
+Ng : 从第N个开始替换,N也会被替换

替换高阶:匹配字符串标记之正则表达式???

# 正则表达式\w\+匹配每一个单词,使用[&]替换它,&对应之前所匹配到的单词:
[root@node01 ~]# echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]

# 这里的正则表达式要加转义字符,不然就很好理解了:s/w+/[&]/g

# 命令中digit 7,被替换成7.样式匹配到的子串是7,\(..\)用于匹配子串,对于匹配到的第一个子串标记为\1
echo this is digita 7 in a number | sed 's/digit \([0-9]\)/\1/'

# Python正则是:
pattern = re.complie(digit ([0-9]),re.S)匹配digit N,最后Result出来是那个数字,而digit是没有的

#将其中的area去掉
1. 或者:匹配多次[a-z]
[root@node01 ~]# echo "Namespaces are one honking great idea " | sed 's/are \([a-z]\+\)/\1/'

2. 或者:重复三次\w
[root@node01 ~]# echo "Namespaces are one honking great idea " | sed 's/are \(\w\{3\}\)/\1/'

3. 或者:直接使用替换
[root@node01 ~]# echo "Namespaces are one honking great idea " | sed 's/ are//g'

这个翻译成Python模式就是:re.complie(area (\w{3}),re.S) , 然后\1是重复匹配到的字符,这里是one


# 上述是只匹配一个结果的,下面是匹配两个结果的
[root@node01 ~]# echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
BBB aaa

sed的匹配需要在()和{}等地方加入转义字符,变成\(\),\{\},但是[]则不需要
---总结:正则表达式是为了更加精确的匹配以及更加灵活的操作

看不懂的替换

把1-10行内所有的abcde替换,注意,正则表达式元字符不能使用这个命令:

[root@node01 ~]# sed '1,10y/ABCDEOM/abcdemo/' mode2
bbbbb omde2 mK!1
-------------------
bbbbb omde2 mK!2
-------------------

删除

#删除空白行
[root@node01 ~]# sed '/^$/d' zen

#删除文件第1行
[root@tenor ~]# sed -i '1d' 1.txt

#删除文件第1~12行,包括1和12行
[root@node01 ~]# sed '1,12d' test.txt

#删除文件的第2行到末尾所有行,开头同理
[root@node01 ~]# sed '1,$d' test.txt

#删除文件最后一行
[root@node01 ~]# sed '$d' test.txt

#删除文件中所有以my开头的行
[root@vagrant-centos65 workspace]# sed '/^my/'d test.txt

#删除文件中所有有is或Is的行
[root@node01 ~]# sed -E '/[I,i]s/d' zen

#删除文件中所有If开头的行
[root@node01 ~]# sed '/^If/d' zen

其他 -e

# sed表达式可以使用单引号来引用,但是如果表达式内部包含变量字符串,就需要使用双引号。
# 我倒觉得可能更多是echo的原因,如果字符串中有变量,单引号会忽略,而双引号会把变量解析以后带入字符串。
[root@node01 ~]# a=hello
[root@node01 ~]# echo hello WORLD | sed "s/$a/HELLO/"
HELLO WORLD
[root@node01 ~]# echo hello WORLD | sed 's/$a/HELLO/'
hello WORLD
[root@node01 ~]# echo "$a"
hello
[root@node01 ~]# echo '$a'
$a



# -e选项允许在同一行里执行多条命令:
# 命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个命令将影响第二个命令的结果。
[root@node01 ~]# nl zen
    1 The Zen of Python, by Tim Peters

    2 Beautiful is better than ugly.
    3 Explicit is better than implicit.
    4 Simple is better than complex.
    5 Complex is better than complicated.
    6 Flat is better than nested.
    7 Sparse is better than dense.
    8 Readability counts.
    9 Special cases aren't special enough to break the rules.
   10 Although practicality beats purity.
   11 Errors should never pass silently.
   12 Unless explicitly silenced.
   13 In the face of ambiguity, refuse the temptation to guess.
   14 There should be one-- and preferably only one --obvious way to do it.
   15 Although that way may not be obvious at first unless you're Dutch.
   16 Now is better than never.
   17 Although never is often better than *right* now.
   18 If the implementation is hard to explain, it's a bad idea.
   19 If the implementation is easy to explain, it may be a good idea.
   20 Namespaces are one honking great idea -- let's do more of those!

[root@node01 ~]# sed -e '15,20d' -e 's/better/-------/g' zen | nl
    1 The Zen of Python, by Tim Peters

    2 Beautiful is ------- than ugly.
    3 Explicit is ------- than implicit.
    4 Simple is ------- than complex.
    5 Complex is ------- than complicated.
    6 Flat is ------- than nested.
    7 Sparse is ------- than dense.
    8 Readability counts.
    9 Special cases aren't special enough to break the rules.
   10 Although practicality beats purity.
   11 Errors should never pass silently.
   12 Unless explicitly silenced.
   13 In the face of ambiguity, refuse the temptation to guess.
   14 Namespaces are one honking great idea -- let's do more of those!

15-20行并且把所有的better替换掉

文件**

# sed '/^xx/r file1' file2
如果file2中有以xx开头的行,就把file1中的内容在下一行打印一边
[root@tenor ~]# sed '/^c/r test.txt' 1.txt | nl
     1    nginxTotal:       2097148 kB
     2    nginxFree:        2097148 kB

     3    cccc
     4     1 aaa is aaa is aaa isaax
     5        2 bb aaa ks aaa ks aaa 
     6        3 asdsdagfjpjadfadfjakldfjk
     7        4 a
     8        5 dgsfg
     9        6 fasggre
    10        7 wgsgt
    11        8 wethynyhyjurtj
    12        9 rhtgf
    13       10 gsgnhtyehjwyet
    14       11 ertwsgfn
    15       12 yjhq3y4twe
    16       13 sgdfbgsacwerebv
    17    ddd
    18    vvv
    19    eeeee
    20    gggg
    21    kkkkk
    22    lll
    23    ccy
    24     1 aaa is aaa is aaa isaax
    25        2 bb aaa ks aaa ks aaa 
    26        3 asdsdagfjpjadfadfjakldfjk
    27        4 a
    28        5 dgsfg
    29        6 fasggre
    30        7 wgsgt
    31        8 wethynyhyjurtj
    32        9 rhtgf
    33       10 gsgnhtyehjwyet
    34       11 ertwsgfn
    35       12 yjhq3y4twe
    36       13 sgdfbgsacwerebv
    37    ccc
    38     1 aaa is aaa is aaa isaax
    39        2 bb aaa ks aaa ks aaa 
    40        3 asdsdagfjpjadfadfjakldfjk
    41        4 a
    42        5 dgsfg
    43        6 fasggre
    44        7 wgsgt
    45        8 wethynyhyjurtj
    46        9 rhtgf
    47       10 gsgnhtyehjwyet
    48       11 ertwsgfn
    49       12 yjhq3y4twe
    50       13 sgdfbgsacwerebv
    51    ccc
    52     1 aaa is aaa is aaa isaax
    53        2 bb aaa ks aaa ks aaa 
    54        3 asdsdagfjpjadfadfjakldfjk
    55        4 a
    56        5 dgsfg
    57        6 fasggre
    58        7 wgsgt
    59        8 wethynyhyjurtj
    60        9 rhtgf
    61       10 gsgnhtyehjwyet
    62       11 ertwsgfn
    63       12 yjhq3y4twe
    64       13 sgdfbgsacwerebv

#写入文件 /w
在1.txt中以c开头的行都被写入test.txt中,test.txt中的内容被覆盖
[root@tenor ~]# sed '/^c/w test.txt' 1.txt | nl
     1    nginxTotal:       2097148 kB
     2    nginxFree:        2097148 kB

     3    cccc
     4    ddd
     5    vvv
     6    eeeee
     7    gggg
     8    kkkkk
     9    lll
    10    ccy
    11    ccc
    12    ccc

[root@tenor ~]# cat test.txt
cccc
ccy
ccc
ccc

# 将This Is A Line追加到mode2以BB开头的行后面:  a\
[root@node01 ~]# sed '/^BB/a\This Is A Line' mode2 | nl
    1 BBBBB MODE2 OK!1
    2 This Is A Line
    3 -------------------
    4 BBBBB MODE2 OK!2
    5 This Is A Line
    6 -------------------
[root@tenor ~]# sed '/^c/a\hhhhhxxx' test.txt | nl
     1    cccc
     2    hhhhhxxx
     3    ccy
     4    hhhhhxxx
     5    ccc
     6    hhhhhxxx
     7    ccc
     8    hhhhhxxx

#在mode2的第2行之后插入This Is A Line          
[root@node01 ~]# sed '2a\This Is A Line' mode2 | nl
    1 BBBBB MODE2 OK!1
    2 -------------------
    3 This Is A Line
    4 BBBBB MODE2 OK!2
    5 -------------------

# #在mode2的第2行之前插入This Is A Line     i\
[root@node01 ~]# sed '2i\This Is A Line' mode2 | nl
    1 BBBBB MODE2 OK!1
    2 This Is A Line
    3 -------------------
    4 BBBBB MODE2 OK!2
    5 -------------------

之前和之后就像一个是insert、一个是append

奇偶np

# 打印奇数行或偶数行

# 偶数行
1、[root@node01 ~]# sed -n 'n;p' mode2
2、[root@node01 ~]# sed -n '1~2p' mode2
    2 -------------------
    4 -------------------


# 奇数行     
1、[root@node01 ~]# sed -n 'p;n' mode2
2、[root@node01 ~]# sed -n '2~2p' mode2
    1 BBBBB MODE2 OK!1
    3 BBBBB MODE2 OK!2

插入

第7行下面加入
[root@tenor ~]# sed '7 a\祝福高杨\n\祝福黄子' 1.txt

nginxTotal:       2097148 kB
nginxFree:        2097148 kB

cccc
ddd
vvv
eeeee
祝福高杨
祝福黄子
gggg
kkkkk
lll
ccy
ccc
ccc

第7行上面加入
[root@tenor ~]# sed '7 i\祝福高杨\n\祝福黄子' 1.txt
nginxTotal:       2097148 kB
nginxFree:        2097148 kB

cccc
ddd
vvv
祝福高杨
祝福黄子
eeeee
gggg
kkkkk
lll
ccy
ccc
ccc

例子

1.显示/etc/passwd文件中位于第偶数行的用户的用户名
[root@localhost ~]# sed -n 'n;p' /etc/passwd | cut -d: -f1
或者
[root@tenor ~]# sed -n '1~2p' /etc/passwd | cut -d: -f1
2.为/tmp/文件中前三行的行首加#号
sed -i '1,3s@(^.)@#\1@g' /tmp/
3.删除/etc/inittab文件中空白行
[root@localhost ~]# sed -i '/^$/d' /etc/inittab
4.删除/etc/vimrc文件中的以#开头,且后面跟了至少一个空白字符的行的#和空白字符
sed -i 's@^#[[:space:]]+@@g' /etc/vimrc
5.利用sed 取出ifconfig命令中本机的IPv4地址
[root@tenor ~]#  ifconfig | sed -r '2!d;s/^(.*inet )(.*)( net.*)/\2/'
172.17.238.167

awk

文本报告生成器,Linux上实现gawk

awk是一个文本分析工具,相对于grep的查找,sed的编辑,awk优势在于对数据分析后形成的报告

awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

将我们的数据格式化输出

name id

a 1

b 2

…… ……
https://wangchujiang.com/linux-command/c/awk.html

[root@localhost ~]# awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...

awk脚本

是由模式和操作组成的。其基本结构为:
awk ‘BEGIN{ print “start” } pattern{ commands } END{ print “end” }’ file

处理流程:
第一步:执行BEGIN{ commands }语句块中的语句;
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{ commands }语句块。

常用选项

参数
-F 指定分隔符
-v 指定用户定义变量,赋值一个用户定义变量,将外部变量传递给awk
-f 从脚本文件读取awk命令

模式PATTERN


    • 模式可以是以下的任意一种


      • 正则表达式:使用通配符的拓展集
      • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试
      • 模式匹配表达式::用运算符~(匹配)和~!不匹配
      • BEGIN、pattern、 END 语句块

action (动作)


    • 操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内
    • 主要组成部分:变脸或数组赋值、输出命令、内置函数、控制流语句

awk运算符


    • 算数运算符:+ - * / & ++ —
    • 赋值运算符:= += -= = /= *= %=
    • 逻辑运算符:|| 或 && 与 !非
    • 关系运算符 > < == !=
    • 正则运算符:~ 匹配正则表达式 ~!与 不匹配正则表达式

awk内置变量

属性 说明
$0 当前记录(作为单个变量)
$1~$n 当前记录的第n个字段,字段间由FS分隔
FS 输入字段分隔符 默认是空格
NF 总列数
NR 已经读出的记录数,就是行号,从1开始
RS 输入的记录分隔符默认为换行符
OFS 输出字段分隔符 默认也是空格
ORS 输出的记录分隔符,默认为换行符
ARGC 命令行参数个数
ARGV 命令行参数数组
FILENAME 当前输入文件的名字
IGNORECASE 如果为真,则进行忽略大小写的匹配
ARGIND 当前被处理文件的ARGV标志符
CONVFMT 数字转换格式 %.6g
ENVIRON UNIX环境变量
ERRNO UNIX系统错误消息
FIELDWIDTHS 输入字段宽度的空白分隔字符串
FNR 当前记录数
OFMT 数字的输出格式 %.6g
RSTART 被匹配函数匹配的字符串首
RLENGTH 被匹配函数匹配的字符串长度
SUBSEP \034
  • 内置变量的用法 ``` [root@tenor ~]# awk -F ‘:’ ‘/root/{print NR,$1,$2}’ /etc/passwd 1 root x 10 operator x

awk -F: ‘{print “fname:”FILENAME,”linenum:”NR}’ /etc/passwd0

打印一行的最后一个字段和倒数第二个字段

[root@hw ~]# awk -F: ‘/root/ {print $(NF-1),$NF}’ /etc/passwd /root /bin/bash /root /sbin/nologin


-v定义变量

只需要把其中的a当作1看就行

[root@hw ~]# awk -F: -v a=1 ‘/root/{print $a,$(a+1)}’ /etc/passwd


- 条件和循环用法
- <br />
   - if (condition) action
   - if (condition) action else action
   - for (initialisation; condition; increment/decrement) action
   - while (condition) action
- <br />
   - <br />
      - break:用以结束循环
      - Continue:语句用于在循环体内部结束本次循环,从而直接进入下一次循环迭代
- 数组
- <br />
   - 数组使用的语法格式:array_name[index]=value
   - 删除数组:delete array_name[index]
   - 多维数组
- 函数
- <br />
   - [https://www.runoob.com/w3cnote/awk-built-in-functions.html#b2](https://www.runoob.com/w3cnote/awk-built-in-functions.html#b2)

<a name="0b9dec77"></a>
### awk编程

[root@hw ~]# seq 6 | awk BEGIN’{sum=0;print “开始” } {print $1”+”;sum+=$1} END {print “结束:sum=”,sum}’ 开始 1+ 2+ 3+ 4+ 5+ 6+ 结束:sum= 21


<a name="af75a73a"></a>
### 常见用法

1. 以:号为分隔符,输出/etc/passwd的第一字段内容<br />
[root[@node1 ]()  ~]# awk -F: '{print $1}' /etc/passwd <br />
[root[@test ]()  tmp]# awk -F: '{print $1"用户shell为:"$7}' /etc/passwd <br />
$0: 代表整行内容
1. 匹配模式:关系表达式:条件为GID为996   动作:用户名称<br />
[root[@node1 ]()  ~]# awk -F: '$4==188 {print $1}' /etc/passwd
1. 匹配模式:正则表达式: 以test为开头的行  动作: 输出 用户名和组id<br />
[root[@node1 ]()  ~]# awk -F: '/^test/{print $1,$4}' /etc/passwd
1. 传递变量 动作:输出 用户名称 和 组ID<br />
[root[@node1 ]()  ~]# awk -F: -va=3 '{print $1,$1+$a}' /etc/passwd
1. 匹配模式: BEGIN和END语句<br />
[root[@node1 ]()  ~]# awk  -F:  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd <br />
[root[@node1 ]()  ~]# awk -F: 'BEGIN{print"-------------------------\n"}{printf "username:%-16s\tsuserid:%-16s\n",$1,$4}END{printf N "%-4s records\n",NR}' /etc/passwd <br />
使用-F指定分隔符,-v传递变量参数,输出时有print和printf格式化输出,并且输出多列用,号分割,并且添加BEGIN和END字段。

<a name="7f6e23cf"></a>
### awk练习题

1.查看cpu使用率

[root@tenor ~]# uptime |awk ‘{print $1,$10}’ 01:37:59 0.01,


2.提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字

[root@tenor ~]# echo “Yd$C@M05MB%9&Bdh7dq+YVixp3vpw” | awk ‘gsub(/[^[:digit:]]/,””,$0)’ 05973


3.统计使用bash的用户个数

[root@tenor ~]# awk ‘BEGIN{x=0} /bash$/{x++} END{print x}’ /etc/passwd 4


4.统计/etc/passwd文件内“root”出现的次数

[root@tenor ~]# awk -F [:/] ‘BEGIN{j=0}{i=1} {while(i<=NF){if($i~/root/){j++};i++}} END{print j}’ /etc/passwd 4


5.打印九九乘法表

[root@tenor ~]# seq 9 | sed ‘H;g’ | awk -v RS=’’ ‘{for(i=1;i<=NF;i++)printf(“%dx%d=%d%s”, i, NR, i*NR, i==NR?”\n”:”\t”)}’ 1x1=1 1x2=2 2x2=4 1x3=3 2x3=6 3x3=9 1x4=4 2x4=8 3x4=12 4x4=16 1x5=5 2x5=10 3x5=15 4x5=20 5x5=25 1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36 1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49 1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64 1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81


<a name="b1bba2a3"></a>
### awk经典案例  nginx 日志

‘$remote_addr - $remote_user [$time_local] “$request” $status $body_bytes_sent “$http_referer” “$http_user_agent” “$http_x_forwarded_for”‘ 统计访问IP次数: awk ‘{a[$1]++}END{for(v in a)print v,a[v]}’ /var/log/nginx/access.log

统计访问访问大于10次的IP: awk ‘{a[$1]++}END{for(v in a){if(a[v]>10)print v,a[v]}}’ /var/log/nginx/access.log

统计访问IP次数并排序取前10: awk ‘{a[$1]++}END{for(v in a)print v,a[v]|”sort -k2 -nr |head -10”}’ /var/log/nginx/access.log

统计时间段访问最多的IP: awk ‘$4>=”[02/Jan/2019:00:02:00” &&$4<=”[31/Jan/2020:00:03:00”{a[$1]++}END{for(v in a)print v,a[v]}’ access.log*

统计上一分钟访问量: date=$(date -d ‘-1 minute’+%d/%d/%Y:%H:%M) awk -vdate=$date ‘$4~date{c++}END{printc}’ access.log

统计访问最多的10个页面: awk ‘{a[$7]++}END{for(v in a)print v,a[v]|”sort -k1 -nr|head -n10”}’ access.log

统计每个URL数量和返回内容总大小: awk ‘{a[$7]++;size[$7]+=$10}END{for(v in a)print a[v],v,size[v]}’ access.log

统计每个IP访问状态码数量: awk ‘{a[$1” “$9]++}END{for(v ina)print v,a[v]}’ access.log

统计访问IP是404状态次数: awk ‘{if($9~/404/)a[$1” “$9]++}END{for(i in a)print v,a[v]}’ access.log ```