zoukankan      html  css  js  c++  java
  • 文本处理之sed

    什么是Sed

    sed是一种流编辑器,它是文本处理中非常有用的工具,能够完美的配合正则表达式使用, 处理时,把当前处理的行存储在临时缓冲区中,称为『模式空间』(patternspace),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。

    sed用法

    功能说明

    sed ----------> stream editor 流编辑 --------> 增删改查,过滤,取行

    sed默认对所有行处理

    语法

    sed [options] [sed-commands] [input-files] ---------------> sed 语句

    input-files 可以是文本,也可以是标准输入

    执行流程

    模式空间:sed 软件在内存里的临时的一个缓存空间,存放读取的内容

    数字处理

    n1[,n2][sed-commands] (n1,n2表示地址范围,n2为可选项)
    10 [sed-commands]  对第10行执行sed命令
    10,20 [sed-commands]  对第10到20行执行sed命令
    10,+20  [sed-commands]  对第10行开始的20行执行sed 命令
    1~2 [sed-commands]  对所有奇数行执行sed 命令(第一行开始,步长为2,直到最后一行)
    2~2 [sed-commands]  对所有偶数行执行sed 命令 (第二行开始,步长为2,直到最后一行)
    10,$ [sed-commands]  对第10行到最后一行执行sed命令
    

    正则匹配/字符串处理

    /zhangyao/ [sed-commands]  匹配zhangyao这一行执行sed 命令
    /zhangyao/,/Alex/ [sed-commands]  匹配zhangyao到Alex 之间的行执行sed命令
    /zhangyao/,$ [sed-commands]  匹配zhangyao这一行到最后一行执行sed命令
    

    混合数字+字符串匹配

    10,/Alex/ [sed-commands]  匹配第10行到包含Alex字段的这一行执行sed命令
    /Alex/,10 [sed-commands]  匹配Alex字段的这一行到第10行执行sed命令
    /zhangyao/,+20 [sed-commands]   匹配包含zhangyao这个字段的这一行到其后的20行执行sed命令
    

    选项说明

    选项 说明
    -n 取消默认输出
    -i 修改文件
    -f 后接sed脚本文件名
    -r 使用扩展正则表达式
    -e 执行多条sed命令
    -i.bak 先备份再替换

    sed命令说明

    [sed-commands]

    命令 说明
    a 追加
    i 插入
    d 删除
    c 替换指定的行
    s 替换指定字符串 ( g 命令的替换标志-全局替换标志)
    p 打印
    $ 结尾

    实例

    添加

    $  cat person.txt 
    101,oldboy,CEO
    102,zhangyao,CTO
    103,Alex,COO
    104,yy,CFO
    105,feixue,CIO
    

    单行增加

    在第三行追加数据

    >>>> 使用命令a
    $  sed -i '2a 106,dandan,CSO' person.txt
    $  sed -n '3p' person.txt 
    106,dandan,CSO
    

    在第二行插入数据

    在第2行添加数据

    >>>> 使用命令i
    $  sed -i '2i 110,yyy,xxx' person.txt 
    $  sed -n '2p' person.txt 
    110,yyy,xxx
    

    多行增加

    在第三行添加三条数据

    $  sed -i '2a 106,dandan,CSO
    107,yyy,xxx
    108,hhpsb,mmm' person.txt 
    $  sed -n '3,5p' person.txt 
    106,dandan,CSO
    107,yyy,xxx
    108,hhpsb,mmm
    

    在第二行添加多条数据

    $  sed -i '2i 106,dandan,CSO
    107,yyy,xxx
    108,hhpsb,mmm' person.txt 
    $  sed -n '2,4p' person.txt 
    106,dandan,CSO
    107,yyy,xxx
    108,hhpsb,mmm
    

    删除

    全部删除

    不加任何地址范围

    $  sed -i 'd' person.txt
    

    删除一行

    $  cat -n person.txt 
         1	101,oldboy,CEO
         2	106,dandan,CSO
         3	107,yyy,xxx
         4	108,hhpsb,mmm
         5	102,zhangyao,CTO
         6	103,Alex,COO
         7	104,yy,CFO
         8	105,feixue,CIO
    $  sed -i '2d' person.txt 
    $  cat -n person.txt 
         1	101,oldboy,CEO
         2	107,yyy,xxx
         3	108,hhpsb,mmm
         4	102,zhangyao,CTO
         5	103,Alex,COO
         6	104,yy,CFO
         7	105,feixue,CIO
    

    批量删除

    $  cat -n person.txt 
         1	101,oldboy,CEO
         2	107,yyy,xxx
         3	108,hhpsb,mmm
         4	102,zhangyao,CTO
         5	103,Alex,COO
         6	104,yy,CFO
         7	105,feixue,CIO
    
    1. 删除第2行到第5行
    $  sed -i '2,5d' person.txt
    $  cat -n person.txt 
         1	101,oldboy,CEO
         2	104,yy,CFO
         3	105,feixue,CIO
    
    1. 删除第2行到最后1行
    $  sed -i '2,$d' person.txt 
    $  cat -n person.txt 
         1	101,oldboy,CEO
    
    $  cat -n person.txt 
         1	     1101,oldboy,CEO
         2	     2107,yyy,xxx
         3	     3108,hhpsb,mmm
         4	     4102,zhangyao,CTO
         5	     5103,Alex,COO
         6	     6104,yy,CFO
         7	     7105,feixue,CIO
    

    删除奇数行 (隔行删除~

    $  sed -i '1~2d' person.txt 
    $  cat -n person.txt 
         1	     2107,yyy,xxx
         2	     4102,zhangyao,CTO
         3	     6104,yy,CFO
    

    打印文件内容(排除oldboy)

    $  sed '/oldboy/d' person.txt
         2107,yyy,xxx
         3108,hhpsb,mmm
         4102,zhangyao,CTO
         5103,Alex,COO
         6104,yy,CFO
         7105,feixue,CIO
    

    替换

    • c选项
    $  sed -i '2c 106,dandan,CSO' person.txt
    $  sed -n '2p' person.txt 
    106,dandan,CSO
    
    • s 选项

      g为全局替换标志

      替换模型

      sed -i 's# # #g' person.txt

      sed -i 's/ / /g' person.txt

      替换模型完整版

      Ms# # #Ng

      Ms 对第M行操作 无g标志,对匹配的第1列处理;如果有g,对这一行操作

      Ng 从第N处/列开始往后全部替换

      Ms Ng 对第M行从第N处匹配替换

    替换指定的行

    $  cat person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    不区分大小写替换i

    $  sed 's#ceo#coo#ig' person.txt 
    1101,oldboy,coo
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    永久关闭SELINUX

    $  sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config 
    $  grep -v '^#' /etc/selinux/config|grep -wi 'selinux'
    SELINUX=disabled
    

    优化ssh配置

    $  grep -wn 'PermitRootLogin' /etc/ssh/sshd_config
    38:#PermitRootLogin yes
    90:# the setting of "PermitRootLogin without-password".
    $  grep -wn 'Port' /etc/ssh/sshd_config
    17:#Port 22
    $  grep -wn 'PermitEmptyPasswords' /etc/ssh/sshd_config
    64:#PermitEmptyPasswords no
    $  grep -wn 'UseDNS' /etc/ssh/sshd_config
    115:#UseDNS yes
    $  grep -wn 'GSSAPIAuthentication' /etc/ssh/sshd_config
    79:GSSAPIAuthentication yes
    
    >>>> 优化
    sed -i.bak 's#GSSAPIAuthentication yes#GSSAPIAuthentication no#' /etc/ssh/sshd_config
    sed -i '20a # ssh configure better
    Port 52113
    PermitRootLogin no
    PermitEmptyPasswords no
    UseDNS no' /etc/ssh/sshd_config
    

    获取ip地址

    $  ip a s eth0
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
        link/ether 00:0c:29:bf:09:c9 brd ff:ff:ff:ff:ff:ff
        inet 192.168.142.40/24 brd 192.168.142.255 scope global noprefixroute eth0
           valid_lft forever preferred_lft forever
           
    >>> 方法1
    $  ip a s eth0 |sed -n '3p'|sed -r 's/.*t (.*)/.*/1/g'
    
    >>> 方法2
    $  ip a s eth0|awk 'NR==3{print $2}'|sed -r 's/(.*)/.*/1/g'
    
    >>>> 方法3
    $  hostname -I
    192.168.142.40 
    
    >>>> 方法4
    $  hostname -i
    192.168.142.40
    

    分组替换

    s#()# 1#g 匹配小括号里的元素

    $  echo "I am oldboy teacher" |sed -r 's#.*am (.*) .*#1#g'
    oldboy
    

    系统开机启动项优化

    >>>> 将服务名弄出来
    $  systemctl list-unit-files|awk '/sshd/{print $1}'
    sshd-keygen.service
    sshd.service
    sshd@.service
    sshd.socket
    
    >>>> 通过分组替换拼字符串
    $  systemctl list-unit-files|awk '/sshd/{print $1}'|sed -r 's/(.*)/systemctl enable 1/g'
    systemctl enable sshd-keygen.service
    systemctl enable sshd.service
    systemctl enable sshd@.service
    systemctl enable sshd.socket
    
    >>>> 通过bash命令将字符串当成命令执行
    $  systemctl list-unit-files|awk '/sshd/{print $1}'|sed -r 's/(.*)/systemctl enable 1/g'|bash
    

    批量重命名文件

    >>>> 创建文件
    $  for i in `seq 1 5`;do touch stu_10299_${i}.jpg;done
    $  ll *.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_10299_1.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_10299_2.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_10299_3.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_10299_4.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_10299_5.jpg
    
    >>>> 拼字符串
    $  ls *.jpg |sed -r 's#([a-Z]+)_[0-9]+_([0-9])+(.*)#mv & 1_23#g'
    mv stu_10299_1.jpg stu_1.jpg
    mv stu_10299_2.jpg stu_2.jpg
    mv stu_10299_3.jpg stu_3.jpg
    mv stu_10299_4.jpg stu_4.jpg
    mv stu_10299_5.jpg stu_5.jpg
    
    >>>> 通过bash命令将字符串当成命令执行
    >>>>方法1
    $  ls *.jpg |sed -r 's#([a-Z]+)_[0-9]+_([0-9])+(.*)#mv & 1_23#g'|bash
    
    >>>>方法2
    $  ls *.jpg |sed -r 's#(.*_).*_(.*)#mv & 12#g'|bash
    
    $  ll *jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_1.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_2.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_3.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_4.jpg
    -rw-r--r--. 1 root root 0 9月  23 16:05 stu_5.jpg
    

    给2行相同的数据中的其中一行加注释

    $  cat fstab 
    derot2npchs03-hcpsc01fi2222:/vol1_HH001QC/q_sysfiles/sapmnt /sapmnt/A2X  nfs        rw,nolock,proto=tcp,rsize=32768,wsize=32768 0 0
    derot2npchs03-hcpsc01fi2222:/vol1_HH001QC/q_sysfiles/sapmnt /sapmnt/A2X  nfs        rw,nolock,proto=tcp,rsize=32768,wsize=32768 0 0
    
    $  sed  -i '1s/derot2npchs03-hcpsc01fi2222.*/#&/1' fstab
    $  grep '^#' fstab 
    #derot2npchs03-hcpsc01fi2222:/vol1_HH001QC/q_sysfiles/sapmnt /sapmnt/A2X  nfs        rw,nolock,proto=tcp,rsize=32768,wsize=32768 0 0
    

    执行命令

    $  cat file.txt 
    /etc/passwd
    /etc/vimrc
    /etc/hostname
    
    $  sed 's#^#ls -ld #e' file.txt
    -rw-r--r--. 1 root root 989 9月  16 17:27 /etc/passwd
    -rw-r--r--. 1 root root 1982 8月   9 11:17 /etc/vimrc
    -rw-r--r--. 1 root root 5 9月  22 09:18 /etc/hostname
    

    说明: 这里就是拼凑字符串, ^每读入file.txt中的一行一行就匹配,然后 执行第二个#后的命令, 命令后面一定要有空格, 相当于从文件读入参数给到命令ls -ld

    获取行号(=)

    $  sed '=' person.txt 
    1
    1101,oldboy,CEO
    2
    2107,yyy,xxx
    3
    3108,hhpsb,mmm
    4
    4102,zhangyao,CTO
    5
    5103,Alex,COO
    6
    6104,yy,CFO
    7
    7105,feixue,CIO
    

    单行输出行号

    $  sed '=' person.txt|sed 'N;s#
    #-->#g' 
    1-->1101,oldboy,CEO
    2-->2107,yyy,xxx
    3-->3108,hhpsb,mmm
    4-->4102,zhangyao,CTO
    5-->5103,Alex,COO
    6-->6104,yy,CFO
    7-->7105,feixue,CIO
    

    取出/etc/services中的5,35,70行

    $  sed -n '5p;35p;70p' /etc/services |sed '='|sed 'N;s#
    #-->#g'
    1--># IANA services version: last updated 2013-04-10
    2-->qotd            17/tcp          quote
    3-->whois++         63/udp          whoispp
    

    不清空数据读入下一行(N)

    不清空模式空间的数据, 以 分隔2行

    $  sed  '=' person.txt |sed 'N;s#
    # #'
    1 1101,oldboy,CEO
    2 2107,yyy,xxx
    3 3108,hhpsb,mmm
    4 4102,zhangyao,CTO
    5 5103,Alex,COO
    6 6104,yy,CFO
    7 7105,feixue,CIO
    

    将文件的内容横向输出

    $  cat 1.txt 
    vsa5228517
    vsa5890477
    vsa5890477
    vsa5890477
    vsa6283258
    $  sed ':a;N;s#
    # #;ta' 1.txt 
    vsa5228517 vsa5890477 vsa5890477 vsa5890477 vsa6283258
    

    说明 : :a ta 是一对符号,:a是先做一个标记,然后如果ta之前执行成功,则跳转到:a标识符继续执行,达到了循环的效果, 可以理解为 :ata之间是 for循环语法中的do和done之间的命令

    横向输出postfix的PID

    $  ps aux |grep postfix|awk 'NR!=1{print $2}'|sed ':a;N;s#
    # #;ta'
    7337 14523 14879
    

    不常用选项

    先执行命令, 再过滤({})

    $  cat person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    
    >>>> 不加{}, 所有的行号都显示
    $  sed -n '2,4p;=' person.txt
    1
    2107,yyy,xxx
    2
    3108,hhpsb,mmm
    3
    4102,zhangyao,CTO
    4
    5
    6
    7
    
    >>>> 将命令放在{}里, 则先执行命令, 然后多条命令的结果再次进行筛选
    >>>> 只显示限制条件的行号
    $  sed '2,4{p;=}' person.txt
    1101,oldboy,CEO
    2107,yyy,xxx
    2
    2107,yyy,xxx
    3108,hhpsb,mmm
    3
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    4
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    打印不可见字符

    格式:sed 'l' <input file>

    $  sed 'l' person.txt 
    1101,oldboy,CEO$
    1101,oldboy,CEO
    2107,yyy,xxx$
    2107,yyy,xxx
    3108,hhpsb,mmm$
    3108,hhpsb,mmm
    4102,zhangyao,CTO$
    4102,zhangyao,CTO
    5103,Alex,COO$
    5103,Alex,COO
    6104,yy,CFO$
    6104,yy,CFO
    7105,feixue,CIO$
    7105,feixue,CIO
    

    转换字符

    格式: sed 'y#待替换字符串#替换字符串#' person.txt

    $  sed 'y#abc#ABC#' person.txt 
    1101,oldBoy,CEO
    2107,yyy,xxx
    3108,hhpsB,mmm
    4102,zhAngyAo,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    退出sed 软件 q

    sed Nq <input file>

    N代表行号, Nq代表在第几行停止读取

    $  sed '3q' person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    

    合并文件

    $  cat num.txt 
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    $  cat person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    
    >>>> 合并文件
    $  sed '$r num.txt' person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    1 1 0 1 0
    

    清空数据读入下一行(n)

    当使用命令n, 则清空, 直接读入下一行

    $  sed -n 'p' person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    
    $  sed -n 'n;p' person.txt 
    2107,yyy,xxx
    4102,zhangyao,CTO
    6104,yy,CFO
    

    说明:读取第一行 1101,oldboy,CEO, 碰到n命令, 直接丢弃, 读下一行 2107,yyy,xxx, 遇到p命令打印, 以此类推

    模拟其他命令

    $  cat person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    模拟cat命令

    $  cat person.txt 
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    
    $  sed "" person.txt
    1101,oldboy,CEO
    2107,yyy,xxx
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    模拟grep -v

    $  grep -v 'yyy' person.txt 
    1101,oldboy,CEO
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    $  sed -n '/yyy/ !p' person.txt 
    1101,oldboy,CEO
    3108,hhpsb,mmm
    4102,zhangyao,CTO
    5103,Alex,COO
    6104,yy,CFO
    7105,feixue,CIO
    

    模拟head 命令

    $  head -2 person.txt
    1101,oldboy,CEO
    2107,yyy,xxx
    $  sed  '3,$d' person.txt
    1101,oldboy,CEO
    2107,yyy,xxx
    

    模拟wc 命令

    $  wc -l person.txt 
    7 person.txt
    $  sed -n '$=' person.txt
    7
    
  • 相关阅读:
    Linux内核空间-用户空间通信之debugfs
    Mysql 启动失败 报错 1067
    [置顶] hdu3018解题报告--也是白话几笔画学习总结
    【Todo】蒙特卡洛(蒙特卡罗)树 & 卷积网络
    基本分类方法——KNN(K近邻)算法
    SVM(支持向量机)与统计机器学习 & 也说一下KNN算法
    可重入锁 & 自旋锁 & Java里的AtomicReference和CAS操作 & Linux mutex不可重入
    【Todo】Nginx架构学习
    【转载】C++异常机制的学习
    关于协程的学习 & 线程栈默认10M
  • 原文地址:https://www.cnblogs.com/cjwnb/p/11607683.html
Copyright © 2011-2022 走看看