字符串处理指令 sed,cut 详解

蹲街弑〆低调 提交于 2020-10-06 09:10:31
  1. cut

    • 语法cut option... [file]...

    • 理解

      可以理解为split函数。

    • 输入

      • 文件

        filename

      • 标准输入

        重定向或-

    • 下标选择

      • n

      等价于

      string.splite(regex)[n]
      
      • n0,n1,n2...

      先对下标进行排序,然后去重,再进行遍历输出。

      • n-m

      范围内的输出,包含关系。

      • -n

      从1到n

      • n-

      从n到末尾,不怕越界,越界为空。

    • 选项

      • -b byte-list|--bytes=byte-list

        按照字节处理

      • -c character-list|--characters=character-list

        按照字符处理

      • -f field-list|--fields=field-list

        按照自定义分隔符进行分割后的多个单词处理。

      • -d input_delim_byte |-d input_delim_byte

        一般和f一起使用,用来声明分隔符的。

      • --output-delimiter=output_delim_string

        输出的分隔符,默认使用-d的分隔符。

        [root@localhost sed]# echo "hello world" | cut -d ' ' -f1- --output-delimiter='----'
        hello----world
        
      • --complement

        输出完整的,而不是残缺的。范围选中的不输出。

        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -f2- -d ' '
        root
        root
        root
        root
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b2-
        r
        r
        r
        r
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b4-
        roo
        roo
        roo
        roo
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b5-
        root
        root
        root
        root
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b8-
        root
        root
        root
        root
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b5-15
        root 0.0  0.4 112924  4296 ?        Ss   Jun11   0:00 /usr/sbin/sshd -D
        root 0.0  0.6 163292  6120 ?        Ss   Jun11   0:01 sshd: root@pts/0
        root 0.0  0.6 163292  6116 ?        Ss   06:19   0:00 sshd: root@pts/1
        root 0.0  0.1 112816   960 pts/1    S+   07:55   0:00 grep --color=auto sshd
        [root@localhost sed]# ps aux | grep "sshd" | cut --complement -b120-
        root      1028  0.0  0.4 112924  4296 ?        Ss   Jun11   0:00 /usr/sbin/sshd -D
        root      1434  0.0  0.6 163292  6120 ?        Ss   Jun11   0:01 sshd: root@pts/0
        root      1974  0.0  0.6 163292  6116 ?        Ss   06:19   0:00 sshd: root@pts/1
        root      2135  0.0  0.1 112816   956 pts/1    S+   07:56   0:00 grep --color=auto sshd
        
  2. sed

    • 简介

      stream editor,流编辑程序。可以用于处理字符流和字节流。

      一般用于处理字符串替换。

    • 工作原理

      • 两个数据缓冲区,开始都为空。处理数据也是一行一行的处理。

      • 一个是读取的数据区,一个是辅助存储区。辅助存储区一般没有用。有一些指令会用到。

      • 一个周期

        • 从字节流中读取一行数据,去除尾部的换行符。保存起来。放在数据缓冲区。
        • 然后执行指令,每一个指令都有一个行地址信息。也就是各自处理的行的范围。
        • 行是作为筛选的重要条件之一,只有满足的才会执行。比如只处理第一行的,那么其他行的行号不合格就会忽略掉,不执行指令。
        • 执行完了所有的指令,如果没有声明-n,就会输出结果到标准输出,并且将之前删除的行位添加上。
        • 执行完毕,再从第一步开始。每次处理完了之后,数据区的数据都会进行清空,也就是上次读取的一行数据,而数据缓冲区将会保留。当然也有部分的指令可以请求不清除。
      • 同时处理多行的指令,大多都是大写,和小写不同的就是可以处理多行。

        • N

          添加一行数据到数据区,也就是一次性处理两条数据,中间的换行符也添加进去了。如果没有读取完整就直接退出。不执行任何处理

          # 可以通过死循环的方式在一个周期内处理所有的数据。可以结合上面的周期解释进行理解。
          [root@localhost sed]# sed -e 'H;s/\n/----/' number.txt
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          [root@localhost sed]# sed -e ':label;N;s/\n/ /;s/ 2$/22222-----/;b label' number.txt
          122222----- 3 4 5 6 7 8 9 10
          [root@localhost sed]# sed -e 'N;N;s/\n/ /;' number.txt
          1 2
          3
          4 5
          6
          7 8
          9
          10
          [root@localhost sed]# sed -e 'N;N;s/\n/ /g;' number.txt
          1 2 3
          4 5 6
          7 8 9
          10
          [root@localhost sed]# sed -e 'N;N;s/\n/ /g;' number.txt
          1 2 3
          4 5 6
          7 8 9
          10
          [root@localhost sed]# sed -n -e 'N;N;s/\n/ /gp;' number.txt
          1 2 3
          4 5 6
          7 8 9
          
        • D

          清理数据区的内容,并开始下一个周期循环。

          # 最后一个因为没有
          [root@localhost sed]# sed -e 'N;N;s/\n/ /g;' number.txt
          1 2 3
          4 5 6
          7 8 9
          10
          [root@localhost sed]# sed -e 'N;N;s/\n/ /g;D;' number.txt
          10
          
    • 输入

      • 文件输入
        sed SCRIPT INPUTFILE INPUTFILE... 
        
      • 重定向
        echo hello | sed SCRIPT -
        
    • 指令选项

      • sed OPTIONS... [SCRIPT] [INPUTFILE...]
      • -n|--quiet|--silent
        • 不输出,除非指令明确的声明。
        [root@localhost sed]# sed -e "2,5d" number.txt
        1
        6
        7
        8
        9
        10
        [root@localhost sed]# sed -n -e "2,5d" -e "1,5p" number.txt
        1
        [root@localhost sed]# sed -n -e "2,4d" -e "1,5p" number.txt
        1
        5
        [root@localhost sed]# cat number.txt
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        
      • -e script|--expression=script

        声明紧接着的字符串按照脚本解析。

      • -f script-file|--file=script-file

        脚本从文件中读取。

      • 如果没有显示声明脚本,默认使用第一个非选项的字符串作为脚本。
      • -i[SUFFIX]|--in-place[=SUFFIX]
        • 将原来的文件添加备份,将处理后的结果作为新的文件。不建议和-n搭配,搭配了就是将显式声明的输出结果写入文件。
         sed -i.bak -e "s/\(*\)/\1/" number.txt
         # 等价于
         sed -e "s/\(*\)/\1/" number.txt > temp.txt
         mv number.txt number.txt.bak
         mv temp.txt number.txt
        
        • 如果没有suffix就是处理结果替换源文件。
        • suffix里用*表示源文件名,一个*表示一个源文件名,多个*就是多个源文件名。
        # 默认后缀
        sed -i.bak -e "s/\(*\)/\1/" number.txt
        # 添加前缀
         sed -ibak* -e "s/\(*\)/\1/" number.txt
        # 多个*
         sed -i**.bak -e "s/\(*\)/\1/" number.txt
        
        #[root@localhost sed]#  sed -i**.bak -e "s/\(*\)/\1/" number.txt
        #[root@localhost sed]# ls
        #baknumber.txt  input.txt  number.txt  number.txt.bak  number.txtnumber.txt.bak
        
        组合选项的时候最好放在i前面,不然就会被按照后缀解析。默认添加了-s选项。
      • -E|-r|--regexp-extended
        • 加强版正则表达式,支持更多匹配符。
        • 默认的是简略版正则。

      • -s|--separate

        • 默认是将多个文件当成一个文件处理。

        • 添加选项后将文件按照多个独立文件处理。

        • -i选项的时候默认添加了这个选项。
    • 退出码

      • 0

        表示成功处理完毕。

      • 1

        表示非法指令,语法错误,正则错误。

      • 2

        文件读写失败,因为权限问题或没有找到。

      • 4

        运行时读写错误。

      • 自定义

        echo | sed ’Q42’ ; echo $?
        # 退出,并获对应的退出码。
        
    • 脚本

      • 声明添加方式

        5种,分别为:-e -f --expression --file和前四个都没有时第一个非选项字符串。

      • 脚本的固定格式[addr]X[options]

        # 替换 s为x后面的为options
        s/aaa//
        # 指定行替换 1,5就是 addr
        1,5s/aaa//
        #/regex/就是addr,这个是用正则来选择行
        /regex/s/aaa// 
        
        addr可以是某一行行号,可以是正则,可以是区间
      • 多个脚本

        可以在一个字符串里面声明多个脚本,也可以通过多次声明多个脚本。

        # 第一个 字符串多个脚本
        sed '/^foo/d ; s/hello/world/' input.txt > output.txt
        # 第二个 多个选项声明多个脚本
        sed -e '/^foo/d' -e 's/hello/world/' input.txt > output.txt
        # 第三个 文件中多行表示多个脚本
        echo '/^foo/d' > script.sed
        echo 's/hello/world/' >> script.sed
        sed -f script.sed input.txt > output.txt
        # 第四个 文件和字符串混合声明多个脚本
        echo 's/hello/world/' > script2.sed
        sed -e '/^foo/d' -f script2.sed input.txt > output.txt
        
      • a,c,i指令因为功能原因,不能用分好作为分隔,所以放在末尾或者文件中声明,或者是换行。
      • 声明脚本最好用单引号,不要用双引号。

    • 脚本之指令|X

      • 回顾

      指令固定格式[addr]X[options],这小结讲的是支持的指令。

      • 某一行后插入a
      # 两种格式切记是
      atext	\
      text\
      text
      #
      a text
      

      案例

      [root@localhost sed]# sed -e '2,5ahello' number.txt
      1
      2
      hello
      3
      hello
      4
      hello
      5
      hello
      6
      7
      8
      9
      10
      [root@localhost sed]# sed -e '2,5a\
      oknice\
      ojbk' number.txt
      1
      2
      oknice
      ojbk
      3
      oknice
      ojbk
      4
      oknice
      ojbk
      5
      oknice
      ojbk
      6
      7
      8
      9
      10
      
      • 删除指令d

      删除指定行

      • 插入i

      语法和a相同,效果是在某一行前面插入。

      • 输出行p
      • 替换 s/regexp/replacement/[flags]

      替换是比较常用的,后面讲。

      • 输出行号 =

      先输出行号在输出对应行的内容。不在同一行。

      [root@localhost sed]# sed -e "=" number.txt
      1
      1
      2
      2
      3
      3
      4
      4
      5
      5
      6
      6
      7
      7
      8
      8
      9
      9
      10
      10
      
      • 字典映射y

      y/src/dst/
      # 案例
      [root@localhost sed]# sed -e 'y/123456789/abcdefghi/' number.txt
      a
      b
      c
      d
      e
      f
      g
      h
      i
      a0
      # 将src字符翻译成dst字符 src和dst长度应该一致
      
      • 输出结果的内容 l

      以类似正则的方式进行输出。数据区的内容,不会有影响。

      [root@localhost sed]# sed -n -e 'N;N;p;l' number.txt
      1
      2
      3
      1\n2\n3$
      4
      5
      6
      4\n5\n6$
      7
      8
      9
      7\n8\n9$
      
    • 指令s/regexp/replacement/flags

      • 这个是常用指令
      • 匹配和替换

      匹配一行字符串,将匹配的部分用后面的replacement进行替换。

      • regex

      regex是正则表达式,正则有一般正则和拓展正则。

      • 匹配组
      • 通过括号就可以形成组。将组内数据作为单独的参数,可以单独的获取。
      • 在后面的替换可以用\n的方式使用。n的范围是1-9,&表示匹配的整个字符串。
      # 注意强正则和弱正则的区别
      [root@localhost sed]# sed -E -e 's/([0-9])/\1\1/' number.txt
      11
      22
      33
      44
      55
      66
      77
      88
      99
      110
      [root@localhost sed]# sed -e 's/\([0-9]\)/\1\1/' number.txt
      11
      22
      33
      44
      55
      66
      77
      88
      99
      110
      [root@localhost sed]# sed -E -e "s/(.{5})/-&-/g" alpha.txt
      -hello--world-
      -hello--world-
      [root@localhost sed]# sed -E -e "s/[hw](.{4})/-&-/g" alpha.txt
      -hello--world-
      -hello--world-
      [root@localhost sed]# sed -E -e "s/[hw](.{4})/-\1&-/g" alpha.txt
      -ellohello--orldworld-
      -ellohello--orldworld-
      [root@localhost sed]# sed -E -e "s/[hw](.{4})/-\1|&-/g" alpha.txt
      -ello|hello--orld|world-
      -ello|hello--orld|world-
      
      • 界限符号/
      • 这个可以修改,以s指令后第一个字符为界限符。包括界限符需要通过反斜杠转义。
      [root@localhost sed]# sed -e 's#1#9#' number.txt
      9
      2
      3
      4
      5
      6
      7
      8
      9
      90
      [root@localhost sed]# sed -e 's;1;9;' number.txt
      9
      2
      3
      4
      5
      6
      7
      8
      9
      90
      [root@localhost sed]# sed -e 'sa1a9a' number.txt
      9
      2
      3
      4
      5
      6
      7
      8
      9
      90
      
      • 替换时大小写转换

      • \L

      将符号后面的都转为小写。lower

      • \l

      将符号后面的第一个转换为小写

      • \U

      将符号后面的都转为大写。upper

      • \u

      将符号后面的第一个转换为大写

      • \E

      停止前面的转换行为。end.

      • 案例

      [root@localhost sed]# sed -E -e 's/(.*)/\U\1\E/' alpha.txt
      HELLOWORLD
      HELLOWORLD
      [root@localhost sed]# sed -E -e 's/(.*)/\u\1\E/' alpha.txt
      Helloworld
      Helloworld
      
      • flags

      支持的flag有很多种

      • g

        默认是只匹配一个,这个匹配所有。

        [root@localhost sed]# sed -E -e 's/(.)/\u\1\E/' alpha.txt
        Helloworld
        Helloworld
        [root@localhost sed]# sed -E -e 's/(.)/\u\1\E/g' alpha.txt
        HELLOWORLD
        HELLOWORLD
        
      • number

        只匹配第n个。如果和g一起用,则是从n开始的后面所有。

        [root@localhost sed]# sed -E -e 's/(.)/\u\1\E/g' alpha.txt
        HELLOWORLD
        HELLOWORLD
        [root@localhost sed]# sed -E -e 's/(.)/\u\1\E/2g' alpha.txt
        hELLOWORLD
        hELLOWORLD
        [root@localhost sed]# sed -E -e 's/(.)/\u\1\E/3g' alpha.txt
        heLLOWORLD
        heLLOWORLD
        
      • 输出指定结果p

        将替换后的结果输出。这种指定的声明方式在使用-n的时候有用。

      • 忽略大小写I i

        加强正则有用

      • 多行匹配模式M m

        按行匹配。比如^ $,没怎么用。

    • 补充指令

      • n

        按照周期来输出指定行。

        [root@localhost sed]# sed -n -e 'n;n;p' number.txt
        3
        6
        9
        # 等价于
        [root@localhost sed]# sed -n -e '0~3p' number.txt
        3
        6
        9
        
      • 一组指令

        使用{}将一组命令变为一个指令。
        [root@localhost sed]# sed -e '1,3{s/1/2/;3d}' number.txt
        2
        2
        4
        5
        6
        7
        8
        9
        10
        

        这种指令只针对某几行。使用和上面的一样。

      • 替换指令c text

        这个指令的原发和i a相同,效果是替换,按行进行替换。

      • 循环指令

        指令可以看成顺序的代码。通过:label的形式创建一个标签。

        然后通过b label,t label的方式进行跳转。

        # 会往复执行lable.
        :lable;
        commands;
        b label| t lable;
        
        • b label

        无条件的跳转到label位置。

        • t label

        无条件的跳转,但是如果上一条语句的替换执行成功,则才会进行当前的,如果没有成功则跳过。

        while(NULL != readline(data))
        {
            lable: //:lable
            /*
             commands
            */
            goto lable;
            if (end)
            {
                exit(0);
            }
        }
        
      • 检测读取状态 N

        在之前的数据的基础上再添加一行。

        while(NULL != readline(data))
           {
               {//N;
                   pre_replace_suuceed = readline(data+len(data)+1);
                   if(!data.endswith("\n"))
                   {
                       end = true;
                   }
               }
               /*
                commands
               */
            take_relace(data); //s/\n/L/;
               if (end)
               {
                   exit(0);
               }
           }
        
      • 处理多行为1行
        [root@localhost sed]#  sed -e ":lable;N;s/\n/L/;b lable" number.txt
        1L2L3L4L5L6L7L8L9L10
        [root@localhost sed]# cat number.txt
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        
        • 等价于
        while(NULL != readline(data))
        {
           lable: //:lable
           {//N;
               pre_replace_suuceed = readline(data+len(data)+1);
               if(!data.endswith("\n"))
               {
                   end = true;
               }
           }
           /*
            commands
           */
           take_relace(data); //s/\n/L/;
           goto lable;
           if (end)
           {
               exit(0);
           }
        }
        
    • 选择行

      • 单一行

        只处理指定行,1表示第一行,$表示最后一行。注意多个文件的时候,表示整个文件流第一行和最后一行,-i -s选项表示每个文件的第一行和最后一行。

      • 多行

        范围选择

      • 正则匹配

        处理满足正则的,后面单独讲。

      • 周期first~step
        • first表示从哪儿开始。
        • step表示周期
      • 取反

        上面的取反。

      • 案例

        [root@localhost sed]# sed -n -e '1p' number.txt
        1
        [root@localhost sed]# sed -n -e '1,3p' number.txt
        1
        2
        3
        [root@localhost sed]# sed -n -e '/1/p' number.txt
        1
        10
        [root@localhost sed]# sed -n -e '/1/!p' number.txt
        2
        3
        4
        5
        6
        7
        8
        9
        [root@localhost sed]# sed -n -e '3~2p' number.txt
        3
        5
        7
        9
        
    • 正则选择行

      • 说明一般正则和加强正则,典型区分就是需不需要用反斜杠转义。
      • /regexp/

        有匹配的列都会算上。正则里面包含了/需要通过\进行声明转义。

      • 范围

        如果范围前大于后,则只选中一个。

        # 选中的行是第一个匹配的行。而且还可以匹配第0行,这里比较特殊。
        (/regex/|number),(/regexp/,/number/)
        # 从 addr1 开始的后面n个
        addr1,+N
        # 从 addr1 开始的周期性的选择。
        addr1,~N
        
      • 自定义分隔符

        # 所有的都相同。通过转义字符声明自己的分隔符。\character
        sed -n ’/^\/home\/alice\/documents\//p’
        sed -n ’\%^/home/alice/documents/%p’
        sed -n ’\;^/home/alice/documents/;p’
        
      • 不分大小写/regexp/I|\%regexp%I

        因为会有小写i这个指令。小写表示插入。

        # 表示匹配b
        [root@localhost sed]# printf "%s\n" a b c | sed '/b/Id'
        a
        c
        # 匹配的地方前面插入d,a表示后面插入。
        [root@localhost sed]# printf "%s\n" a b c | sed '/b/id'
        a
        d
        b
        c
        
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!