烦恼一般都是想太多了。

0%

How SED works

Linux下三大神器之一的sed,为你处理字符,批量替换,提供了超级效率的操作方法。
sed是面向流(stream),更确切的说是字符流,以行为单位进行操作。循环直至结束。

工作机制

sed 使用了两个数据缓存器 活动的 pattern space, 辅助的 hold space 。其刚开始命令的时候都是空的。
sed 按以下循环进行工作:

  1. sed读取输入文件的一行,移除尾部的换行符,然后放入pattern_space
  2. 执行命令。每个命令都可以指定执行的位置。
  3. 执行完毕后,如果没有打开-n选项就会将 pattern space 内容进行输出,并加上删除掉的换行符。
  4. 回到 [1.]

处理完一行,通常(某些情况我们可以使它保留)是将 pattern_space 清空,但并不清空 hold_space
对于每一个命令,我们都可以给它指定执行的范围(某一行,或,某一范围)。

理解 sed 每次只会读取输入的一行到缓冲区,对与理解 nN命令非常有用。

命令格式

通常情况下我们是这样使用sed的:

sed OPTIONS... [SCRIPT] [INPUTFILE...]

Options

OPTIONS可以说如下值[多个]

--help 帮助
--version 版本信息
-n --quiet --silent 默认情况下,完成一行的处理后,sed默认打印pattern space的内容,此选项将关闭默认打印。
-e SCRIPT --expression=SCRIPT 指定执行的命令,可以多次使用。当然,也可以用{}进行分组指定。
-f SCRIPT-file --file=SCRIPT-file 在文件中指定执行命令。
-i 直接修改输出到文件,而不是到标准输出
-l N | --line-length=N 指定l命令换行的长度。长度为0表明从不换行,如果没有指定的话,值就是70。
-b --binary 当操作系统区别文本文件和二进制文件的时候有用。
--follow-symlinks 指定-i选项的时候,如果输入文件是一个符号链接则会跟随链接到文件。默认情况是不跟随。
-E | -r | --regexp-extend 扩展正则表达式。
-u | --unbufferd 尽量少的缓存输入和输入。(当用tail -f作为输入的时候,这个选项可以让你尽快的看到结果)

退出状态

  • 0 success
  • 1 Invalid command
  • 2 One or more input file specified could not be opend
  • 4 An I/O error。

范围的指定

我们可以指定动作执行的范围(文件中的哪些行),及需要执行的命令( pattern_space )上执行。
number 一个确切的数字,指定某行
$ 最后一行
first~step first=起始 step=步长,想取奇数行就用 1~2,每五行就用 1~5。 GNU SED扩展
/regexp/ 满足正则表达式的行。如果正则表达式内包含/,需要使用\进行转义。
\%regexp% 为了避免上面那样的反引,你可以用任何一个符号来代替%
/regexp/I \%regexp%I 以大小写不敏感的方式来匹配正则式。 GNU 扩展
/regexp/M \%regexp%M 多行模式匹配正则式。这个时候^表示其前有一个换行,$表示其后跟随一个换行。 GNU扩展
ADDR1,+N ADDR1及其后的N行。 GNU 扩展
ADDR1,~N 找到ADDR1后的,继续匹配直到是N的倍数的行。 注意与first~step区别,这条是匹配到了就不继续匹配了,而first-step是匹配到结束。 GNU 扩展
! 跟随在一个地址范围后,其意义是就是不匹配地址范围表达式的才会被选择。 GNU扩展

常用的命令

# 注释
q [EXIT-CODE] 只接受一个地址范围参数,打印当前 pattern_ space 后退出,并返回退出码。 GNU扩展
d 删除当前 pattern_ space,立即开始处理下一行,不会继续执行之后的命令。

seq 3 | sed 2d 
seq 3 | sed 

D 如果 pattern_ space 没有 换行符,等同于d命令。否则,将 pattern_ space 内容删除到第一个换行符为止,然后重新在 pattern_ space 上执行命令,并不会读入下一行到 pattern_ space
p 打印当前 pattern_ space 到标准输出,一般跟 -n选项配合使用

seq 3 | sed -n 2p

P 打印 pattern_ space 到出现第一个换行符的位置
n 如果自动打印没有被-n关闭,此命令会打印当前 pattern_ space, 然后把内容替换为下一行,如果没有输入了,就停止执行命令。
这个命令对于跳过某些行非常有用,比如处理每 Nth行。

seq 6 | sed 'n;n;s/./x/'

Npattern_ space 添加一个换行符 同时将下一行的输入读进来。如果没有输入,不执行命令即退出。
{commands} 一连串命令集合,以’;’分割开的多条命令,在 pattern_ space 上执行。 GNU特性

seq 3 | sed -n '2{s/2/X/ ; p} 

s 替换命令

命令原型:

s/REGEXP/REPLACEMENT/FLAGS 

/号同样可以用 其他符号代替,如:# % 等等避免/需要用转义
工作流程是
用REGEXP匹配 pattern_ space 如果成功,就用REPLACEMENT替换。
REGEXP 可以用 ‘(‘ ‘)‘进行分组,
在REPLACEMENT,可以用 \1..9 进行引用,&代表整个匹配的内容

GNU扩展 内 你还用一组’\’跟’L’,’l’,’U’,’u’,’E’ 组成的序列。但这些并不常用。
\L 将REPLACEMENT变换为小写,直到 \U or \E出现。
\l 将REPLACEMENT中的下一个字符转变为小写.
\U 将REPLACEMENT变换为大写,直到 \L or \E出现。
\u 将REPLACEMENT中的下一个字符转变为大写.
\E 在REPLACEMENT中结束\L,\U的作用。

FLAGS:
g 替换 pattern_ space 内所有匹配的位置。不加此标志,只替换第一次匹配的位置
NUMBER 替换 pattern_ space 内第NUMBER匹配位置。(POSIX内并 没有定义 NUMBER 与g一起使用会是什么情况,GNU内,则表示从第NUMBER到最后一个匹配的位置)
w FILENAME 如果s命令成功执行,将输出写到文件内。GNU扩展 支持使用/dev/stdout /dev/stderr
e 如果s命令匹配成功,在 pattern_ space 内的内容将会被当作命令执行,同时 pattern_ space被替换为命令的输出。 GNU 扩展
p 打印出匹配后的 pattern_ space。同时指定eppe 效果是不一样的。pe将会打印找到的命令,然后打印e输出,ep只是打印e的输出
I,i 以大小写不敏感的方式来匹配正则式。GNU 扩展
M,m 多行模式匹配正则式。这个时候^表示其前有一个换行,$表示其后跟随一个换行。GNU扩展

y 命令

y/SOURCE_CHARS/DEST-CHARS/

逐个替换为对应位置的字符比如 y/abc/ABC/ 凡 a被替换为A b替换为B

其他命令

a\
TEXT
(append)在当前循环输出后面加上TEXT。如果你用-n命令关闭了打印的话,则只打印TEXT

seq 3 | sed '2a\hello'

i\
TEXT
(insert)在当前输出前加上TEXT

seq 3 | sed '2i\hello' 

c\
TEXT
删除 pattern_ space 打印TEXT

seq 3 | sed '2c\hello'

= 打印当前输入的是第几行,后面跟随一个换行符
l N 清晰的模式打印 pattern_ spaceN是行宽,中文全变成\232 \245这样的的了。行尾加上$
r FILENAME 读取文件到当前循环的输出流后。文件名不存在也没事,就当读了个空。 GNU扩展支持 /dev/stdin

seq 3 | sed '2r/etc/passwd'

w FILENAMEpattern_ space 写到文件。 GNU扩展支持/dev/stderr /dev/stdout 文件将被创建(当不存在)或被截短(当已存在),在没有读入行之前。所有w指令(包括s成功执行的w标志)不会关闭或者重新打开文件(提高效率)

seq 3 | sed '2woutfile'

hpattern_ space 的内容替换 hold_ space
Hhold_ space 后加一个换行符 同时把 pattern_ space 的内容copy 过来
ghold_ space 的内容替换 pattern_ space的内容
Gpattern_ space 后加一个换行符 同时把 hold_ space 的内容copy 过来
x 交换 pattern_ spacehold_ space的内容
: LABEL 设置个标签
b LABEL 无条件跳往 LABEL标签。下一循环开始的时候,将会忽略这个标签
t LABEL s成功执行后跳转到LABEL标签

标签使用

<<<<<<< HEAD
标签主要使用 :, t, b三个命令实现的,分别是 设置标签,替换成功后跳转,无条件跳转三个意思。

=======

7fa33ff02a6d163b73353e437388e527d9d7fefe
使用标签可以让我们进入大师的行列。我们要明白的是,我们设置的标签,只是在当前的buffer内执行动作。比如,我们要给 123456789 加上千分号,变成 123,456,789这样:

sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' file

这先执行一个标签,然后匹配 pattern_space中的内容并进行替换,如果替换成功了,就跳转到标签,继续进行替换。有点类似 while循环的意思。

居中

我们可以以79个字符为宽度把文本居中:

sed -e :a -e 's/^.\{1,77\}/ & /'