zoukankan      html  css  js  c++  java
  • Linux 文本处理三剑客

    一、grep:文本过滤工具

    grep 语法格式:

    grep [OPTIONS] PATTERN   [FIFE]
    grep   参数     匹配模式  查找的文件
    
    参数选项 解释说明
    -v 显示不匹配的行,或者说排除某些行,显示不包含匹配文本的所有行
    -n 显示匹配行及行号
    -i 不区分大小写(只适用于单字符),默认是区分大小写的
    -c 只统计匹配的行数,注意不是匹配的次数
    -E 使用扩展的 egrep 命令
    --color=auto 为 grep 过滤的匹配字符串添加颜色
    -w 只匹配过滤的单词,单词的两边必须是非字符符号(即不能是字母数字或下划线)
    -o 只输出匹配的内容

    有文本如下(test.txt)

    test
    dongye
    oldboy
    
    linux
    ubuntu
    centos
    
    LOL
    dota2
    i like playing dota2
    

    1.1 -v 参数实践

    # 过滤不包含oldboy字符串的行,注意被过滤的字符串,尽可能使用双引号
    grep -v "dota2" test.txt
    
    >>>
    test
    dongye
    oldboy
    
    linux
    ubuntu
    centos
    
    LOL
    

    提示: grep 的 -v 参数的作用是排除,默认是以行为单位排除包含参数后面所接内容的某些行

    1.2 -n 参数实践

    # 输出包含 oldboy 字符串的行,并显示行号
    grep -n "dota2" test.txt
    
    >>>
    1:dota2
    2:i like playing dota2
    

    提示: -n 参数会对 grep 命令找到的内容在开头加上对应的行号

    1.3 -i 不区分大小写参数实践

    grep "lol" test.txt
    
    >>>
    找不到值
    grep -i "lol" test.txt
    >>>
    LOL
    

    1.4 -E 和 --color 的参数实践

    # 默认不支持多条件匹配
    grep "like|dota2" test.txt
    
    # 多条件匹配,加 -E
    grep -E "like|dota2" test.txt   
    
    >>>
    dota2
    i like playing dota2
    
    # 加颜色
    grep -Ei --color=auto "like|dota2" test.txt
    

    1.5 -c 参数实践

    grep "dota2" test.txt
    
    >>>
    dota2
    i like playing dota2
    
    # 只想计算匹配的字符串的数量
    grep -c "dota2" test.txt
    
    >>>
    2
    

    1.6 -o 参数实践

    # 注意这里没有 双引号
    grep -o dota2 test.txt
    
    >>>
    dota2
    dota2
    

    1.7 -w 参数实践

    grep -w "like" text.txt
    
    # 结果为空
    

    1.8 grep 常用

    # 查找指定进程
    ps -ef | grep nginx
    
    # 查找指定进程并统计数量
    ps -ef | grep -c nginx
    
    # 从文件中查找关键字
    grep 关键字 test.txt
    
    # 从文件中查找关键字并输出它的行号
    grep -n 关键字 text.txt
    
    # 从多个文件中查找关键字
    grep 关键字 test1.txt test2.txt test3.txt
    
    # 从文件中查找关键字后,再从结果中找到指定关键字
    cat text.txt | grep -v 不要的关键字 | grep -w 要的单词
    ps -ef | grep dub-finance | grep -v grep | awk '{print $2}' | xargs kill -9
    
    # 找出文件中的空白行
    grep -n "^$" test.txt
    
    # 显示当前目录下面以 .txt 结尾的文件中的所有包含每个字符串至少有4个连续小写字符的字符串的行
    grep -n '[a-z]{4}' *.txt
    

    二、sed:字符流编辑器

    语法格式

    sed [选项] [sed内置命令字符] [输入文件]
    

    说明:

    1. sed以及后面的选项、命令和输入文件,每个元素之间都至少要有一个空格。
    2. 【sed内置命令字符】,既可以是单个命令,也可以是多个命令参数的组合
    3. 【输入文件】为sed 需要处理的文件,这是可选项,sed 还能够从标准输入如管道中获取输入

    2.1 选项、内置命令说明

    参数选项

    参数选项 解释说明
    -n 取消默认的sed的输出,常与sed内置命令的p连用
    -i 直接修改文件内容,而不是输出到终端。如果不使用 -i 选项,则sed只是修改内存中的数据,并不会影响磁盘上的文件

    sed内置命令字符

    sed的内置命令字符 解释说明
    a 全拼 append,表示追加文本,在指定行后添加一行或多行文本
    d 全拼 delete,表示删除匹配行的文本
    i 全拼 insert,表示插入文本,在指定行前添加一行或多行文本
    p 全拼 print,表示打印匹配行的内容,通常 p 会与选项 -n 一起使用
    s/regexp/replacement 匹配 regexp 部分的内容,用 replacement 替换 regexp 匹配的内容,regexp部分可以使用正则表达式,在 replacement 部分可以使用特殊字符 & 和 1-9等匹配 regexp 部分的部分内容。在实战场景中,s/regexp/replacement/g 结尾常与g匹配做全局的替换

    2.2 示例文本

    先准备一个文本 tex.txt

    101,oldboy,CEO
    102,zhangyao,CTO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2.3 在文本指定行后追加文本

    sed "2a 106,dandan,CSO" test.txt
    
    >>>
    101,oldboy,CEO
    102,zhangyao,CTO
    106,dandan,CSO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2a 106,dandan,CSO的意思:

    1. 2 表示对第 2 行进行操作,其他的行忽略
    2. a 表示追加,2a 即在第 2 行后追加文本
    3. 2a 后面加上空格,然后接着输入想要追加的文本内容(106,dandan,CSO`)即可

    2.4 在文本指定的行前面插入文本

    sed "2i 106,dandan,CSO" text.txt
    
    >>>
    101,oldboy,CEO
    106,dandan,CSO
    102,zhangyao,CTO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2i 106,dandan,CSO的意思:

    1. 2 表示对第 2 行进行操作,其他的行可忽略
    2. i 代表插入的意思,2i 表示在第2行即当前行插入文本,即插入到第二行
    3. 2i 后面加上空格,然后跟上要插入的文本(106,dandan,CSO),最后接上要处理的文件 text.txt

    2.5 在文件指定行后追加多行文本

    sed "2a 106,dandan,CSO
    107,bingbing,CCO" text.txt
    
    >>>
    101,oldboy,CEO
    102,zhangyao,CTO
    106,dandan,CSO
    107,bingbing,CCO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2.6 删除文件中一行指定的文本

    sed "2d" text.txt
    
    >>>
    101,oldboy,CEO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2.7 删除文件中指定的多行文本

    sed "2,5d" text.txt
    # 表示删除 2-5 行,所以结果只剩下一行
    >>>
    101,oldboy,CEO
    

    2.8 使用sed命令替换文本内容

    sed "s#zhangyao#dandan#g" text.txt
    
    >>>
    101,oldboy,CEO
    102,dandan,CTO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    

    2.9 打印输出文件的指定行的内容

    sed "2p" text.txt
    
    # 这里使用了 sed 内置命令 p 来实现查询功能,并结合数字地址指定查询第2行的内容,但是我们会发现结果不只是输出第2行,文件的其他内容也显示出来了,这是因为 sed 命令有一个默认输出的功能.
    >>>
    101,oldboy,CEO
    102,zhangyao,CTO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CTO
    
    
    sed -n "2p" text.txt
    
    # 为了解决上面命令显示多余内容的问题,使用选项 -n 取消默认输出,只输出匹配行的文本,因此大家只需要记住使用命令 p 必用选项 -n
    >>>
    102,zhangyao,CTO
    
    
    sed -n "2,4p" text.txt
    # 输出 2-4 行
    >>>
    102,zhangyao,CTO
    103,Alex,COO
    104,yy,CFO
    

    2.10 -i 选项

    	这个选项的作用是能够实际修改文件的内容,前面几个例子操作完命令之后,文件的内容并没有发生变化,这是因为 sed 命令默认操作的是内存中的数据,如果想要真正地修改文件的内容,就需要使用选项 `-i`将修改写到磁盘文件上。
    

    2.11 N 内置命令

    有文件如下

    stu10309
    7f754wdw
    stu10123
    faioj322
    stu12452
    fasdassa
    ...
    

    现在要把格式变成

    stu10309=7f754wdw
    stu10123=faioj322
    stu12452=fasdassa
    

    可用以下方法实现

    sed "N;s#
    #=#g" text.txt
    
    	sed 内置命令 N 的作用:不会清空模式空间的内容,并且从输入文件中读取下一行数据,追加到模式空间中,两行数据以换行符 
     连接。
    
    	第一行是 `stu10309` 存入模式控件,碰到命令 `N`,读取第二行 `7f754wdw`,此时模式空间的内容为 `stu10309
    7f754wdw`;然后执行 `s#
    #=#g` 将 `
    `替换为 `=`,即为 `stu10312=`7f754wdw`,输出到屏幕中,第一个循环结束;后面的循环和前面的思路一样,直到文件结束。
    

    三、awk 基础入门

    	不仅是Linux系统中的一个命令,而且还是一种编程语言。是Linux系统最强大的文本处理工具,没有之一。
    

    3.1 参数选项及说明

    awk 命令的常用功能 简要例子说明
    指定分隔符显示某几列 awk -F "GET|HTTP" '{print $2}' test.log 直接取出显示出日志文件的 url 这一列
    通过正则表达式取出你想要的的内容 awk '$6~/Failed/{print $11}' /var/log/secure 分析生产环境中的日志找出谁在破解用户的密码
    显示出某个范围内的内容 awk 'NR20,NR30' filename 显示文件的20到30行内容
    通过awk进行统计计算 awk '{sum+=$0}END{print sum}' ett.txt 计算总和
    awk数组计算与去重 awk '{array[$1]++}END{for(key in array)print key,array[key]}' access.log 对日志进行统计与计数
    awk  [option]  'pattern{action}' file ...
           参数         '条件{动作}'    文件 ... 
    

    参数选项及说明

    参数选项 解释说明
    -F 指定字段分隔符
    -v 定义或修改一个 awk 内部的变量

    3.2 示例文本

    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/mologin
    adm:x:3:4:adm:/var/adm:/sbin/lologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool?mail:/sbin/nologin
    uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
    

    3.3 显示文件中的第5行

    cat -n test.txt   # 先打印内容并在每行内容的开头显示行号
    
    awk 'NR==5' test.txt
    
    	首先NR 在awk中表示行号(记录号),NR==5表示行号等于5的行。这里需要注意的是必须使用两个等号,在awk中两个等号表示 ”等于“,一个等号表示赋值,即向一个变量里面放置内容。
    

    注意:awk后面所接的内容要用单引号

    显示一部分行的内容,例如显示 2-6 行

    awk 'NR==2,NR==6' test.txt
    

    3.4 用 awk 实现给文件每行的内容之前加上行号

    awk '{print NR,$0}' test.txt
    

    这里的NR还是表示行号,$0 表示一整行的内容(一行的内容)。

    3.5 显示第 2 行到 第 6 行,并打印行号

    awk 'NR==2,NR==6 {print NR,$0}' test.txt
    

    3.6 显示文件的第 1 列、第 3 列和最后一列

    awk -F ":" '{print $1,$3,$NF}' test.txt
    
    	这里我们使用了 awk 的 -F参数。-F表示指定一个`分隔符`来切割每一行的内容,-F后面可用单双引号或不加引号,但是,建议加双引号。
    
    	`$1`表示根据分隔符分割的第一列,`$2`表示根据分隔符分割的第二列,以此类推。
    
    	`$0`表示整行。`$NF`表示最后一列。
    

    3.7 把文件中的 /sbin/nologin 替换为 /bin/bash

    awk '{gsub("/sbin/nologin","/bin/bash",$0);print $0}' test.txt
    

    3.8 生产案例1:取出 eh0 网卡对应的ip地址

    ifconfig eth0
    
    >>>
    eho Link encap:Ethernet Hwaddr 00:0C:29:93:49:99
    inet addr:10.0.0.8 Bcast:10.0.0.255 Mask:255.255.255.0
    ...
    

    ​ 取出的方式

    ifconfig eth0|awk -F "(addr:)|(  Bcast:)" 'NR==2{print $2}'
    >>>
    10.0.0.8
    

    ​ 我们的目标是取得ip,本例是10.0.0.8,ip的左边是 addr:,右边是 Bcast:。所以两边都是分隔符,就可以取到我们想要取到的值。(这里需要注意-F 指定多分割符的写法

    ​ 还有一个简单的方法

    ifconfig eth0|awk -F "[ :]+" 'NR==2{print $4}'
    

    ​ 结合起来,-F "[ :]+"就是以单个或连续的空格或冒号或者它们的组合为分隔符。最后就可以获得我们想要的ip地址。

    3.9 面试题--统计域名访问次数

    测试数据如下:

    http://www.etiantian.org/index.html
    http://www.etiantian.org/1.html
    http://post.etiantian.org/index.html
    http://mp3.etiantian.org/index.html
    http://www.etiantian.org/3.html
    http://post.etiantian.org/2.html
    

    3.9.1 方案1

    (1)取出每行中的域名

    awk -F '/' '{print $3}' test.txt
    
    >>>
    www.etiantian.org
    www.etiantian.org
    post.etiantian.org
    mp3.etiantian.org
    www.etiantian.org
    post.etiantian.org
    

    (2)排序(让相同的域名相邻)

    awk -F '/' '{print $3}' test.txt|sort
    

    (3)去重计数

    awk -F '/' '{print $3}' test.txt|sort|uniq -c
    

    3.9.2 方案2(awk数组方案)

    (1)取出域名

    awk -F '/' '{print $3}' test.txt
    

    (2)创建一个 awk 数组,然后把第二列(域名)作为数组的下标,再通过类似于 i++ 的形式来计算域名重复的次数

    awk -F '/' '{hotel[$3]}' test.txt  # 创建 awk 的hotel 数组
    awk -F '/' '{hotel[$3];print $3}' test.txt  #创建 awk 的hotel 数组,并通过 print 输出元素名字(房间号码),注意,这里没输出数组,所以看到的还是第一阶段的内容
    
    >>>
    awk -F '/' '{print $3}' test.txt
    

    (3)开始统计

    awk -F '/' '{hotel[$3]++;print $3,hotel[$3]}' test.txt
    
    >>>
    www.etiantian.org 1
    www.etiantian.org 2
    post.etiantian.org 1
    mp3.etiantian.org 1
    www.etiantian.org 3
    post.etiantian.org 2
    

    (4)输出最终结果

    上面的命令详细地显示了 awk 统计的过程。如果想要获得最终结果该怎么办呢?通过END模式来输出最终结果。

    awk -F '/' '{array[$3]++}END{
    print "www.etiantain.org",array["www.etiantian.org"];
    print "post.etiantian.org",array["post.etiantian.org"];
    print "mp3.etiantian.org",array["mp3.etiantian.org"];
    }' test.txt
    

    awk数组提供了自己独有的方法来完成它——一个专用的循环:

    awk -F '/' '{hotel[$3]++}END{for(domain in hotel)print damain,hotel[domain]}' test.txt
    
    >>>
    mp3.etiantian.org 1
    post.etiantian.org 2
    www.etiantian.org 3
    
    
  • 相关阅读:
    HDU 2844 Coins(多重背包)
    HDU 4540 威威猫系列故事——打地鼠(DP)
    Codeforces Round #236 (Div. 2)
    FZU 2140 Forever 0.5
    HDU 1171 Big Event in HDU(DP)
    HDU 1160 FatMouse's Speed(DP)
    ZOJ 3490 String Successor
    ZOJ 3609 Modular Inverse
    ZOJ 3603 Draw Something Cheat
    ZOJ 3705 Applications
  • 原文地址:https://www.cnblogs.com/dongye95/p/14450235.html
Copyright © 2011-2022 走看看