得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

sed 与替换

只是介绍一下 sed 用作文本替换时的常见做法

sed(stream editor) 的基本工作方式:

  1. 将文件以为单位读取到内存(模式空间)
  2. 使用 sed 的每个脚本对该行进行操作
  3. 处理完成后输出该行

以下的例子均使用下述测试文件 test.txt

1
2
3
4
$ cat test.txt
1 a b c
2 b c d
3 x y z

sed 的替换 s

  1. 基本用法:sed ‘s/old/new/’ filename

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ sed 's/a/*/' test.txt  # 单个替换命令
    1 * b c
    2 b c d
    3 x y z

    $ sed 's/a/*/;s/b/!/' test.txt # 多个替换命令
    $ sed -e 's/a/*/' -e 's/b/!/' test.txt # 与上一条等价
    1 * ! c
    2 ! c d
    3 x y z
  2. 替换并写入文件:sed ‘s/old/new/’ -i filename

    1
    2
    3
    4
    5
    $ sed 's/a/*/' -i test.txt
    $ cat test.txt
    1 * b c
    2 b c d
    3 x y z
  3. 结合正则表达式的替换:sed ‘s/正则表达式/new/’ filename 或 sed -E ‘s/扩展正则表达式/new/’ filename

    1
    2
    3
    4
    $ sed 's/[0-9]/*/' test.txt  # 将数字替换为 *
    * a b c
    * b c d
    * x y z

sed 的替换 s 结合标志位:s/old/new/标志位

  1. 标志位:数字或 g,指定行替换的范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ sed 's/[a-d]/*/g' test.txt  # g 为全行替换,将每一行所有属于 a-d 范围内的字符替换为 *
    1 * * *
    2 * * *
    3 x y z

    $ sed 's/[a-d]/*/2' test.txt # 将每一行第二个属于 a-d 范围内的字符替换为 *
    1 a * c
    2 b * d
    3 x y z

    $ sed 's/[a-z]/*/2g' test.txt # 将每一行第二个及后续所有属于 a-z 范围内的字符替换为 *
    1 a * *
    2 b * *
    3 x * *
  2. 标志位:p 打印替换后的内容

    1
    2
    3
    4
    5
    6
    7
    8
    $ sed 's/[a-d]/*/p' test.txt  # 奇数行的输出是标准输出,sed 处理完默认会输出该行;偶数行则是 p 打印的输出,仅打印输出替换后的行
    1 * b c
    1 * b c
    2 * c d
    2 * c d
    3 x y z

    $ sed -n 's/[a-d]/*/p' test.txt # -n 表示处理完不进行标准输出
  3. 标志位:w 将替换后的内容写入文件

    1
    2
    3
    4
    5
    6
    7
    $ sed 's/[a-d]/*/w test_w.txt' test.txt  # 将每一行第一个属于 a-d 范围内的字符替换为 *,并写入 test_w.txt
    1 * b c
    2 * c d
    3 x y z
    $ cat test_w.txt
    1 * b c
    2 * c d

sed 的替换 s 学会寻址之后,即只对指定行操作,多条命令用 {}

  1. 正则寻址:sed ‘/正则表达式/s/old/new/’ filename

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ sed '/[13]/s/[cx]/*/' test.txt  # 找到存在 1 或 3 的行,将匹配行中的第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b c d
    3 * y z

    $ sed '/[13]/{s/[cx]/*/;s/*/8/}' test.txt # 找到存在 1 或 3 的行,将匹配行中的第一个 c 或第一个 x 替换为 *,第一个 * 替换为 8
    1 a b 8
    2 b c d
    3 8 y z
  2. 数字寻址:sed ‘数字s/old/new/’ filename

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ sed '2s/[cx]/*/' test.txt  # 将第二行中的第一个 c 或第一个 x 替换为 *
    1 a b c
    2 b * d
    3 x y z

    $ sed '2{s/[cx]/*/;s/*/8/}' test.txt # 将第二行中的第一个 c 或第一个 x 替换为 *,再将第二行中的第一个 * 替换为 8
    1 a b c
    2 b 8 d
    3 x y z
  3. 范围寻址,可以是行号范围,可以是正则表达式匹配的范围,可以是混合的范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ sed '/[1d]/,$s/[cx]/*/' test.txt  # 从包含 1 或 d 的行开始,到最后一行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b * d
    3 * y z

    $ sed '2,$s/[cx]/*/' test.txt # 从第二行开始,到最后一行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b c
    2 b * d
    3 * y z

    $ sed '/a/,/b/s/[cx]/*/' test.txt # 从包含 a 的行开始,到包含 b 的行结束,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b * d
    3 x y z
  4. 特殊的范围寻址:m~n(m、n 均为数字)、m,+n(m 可以是数字可以是正则、n 为数字)、m,~n(m 可以是数字可以是正则、n 为数字)

    • m~n 表示应该处理 m 行开始的每 n 行
    • m,+n 表示从第 m 行以及下面 n 行
    • m,~n 表示从第 m 行开始到 n 的第一个倍数行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $ sed '1~2s/[cx]/*/' test.txt  # 从第二行开始,每两行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b c d
    3 * y z

    $ sed '2,+1s/[cx]/*/' test.txt # 从第二行开始,往后一行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b c
    2 b * d
    3 * y z

    $ sed '/a/,+1s/[cx]/*/' test.txt # 从包含 a 的行开始,往后一行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b * d
    3 x y z

    $ sed '2,~1s/[cx]/*/' test.txt # 从第二行开始,到 1 的第一个个倍数行,即第三行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b c
    2 b * d
    3 * y z

    $ sed '/a/,~1s/[cx]/*/' test.txt # 从包含 a 的行开始,到 1 的第一个个倍数行,即第二行,将范围内的行中第一个 c 或第一个 x 替换为 *
    1 a b *
    2 b * d
    3 x y z

be yourself, everyone else is already taken.