# 简介

sed 编辑器被称作流编辑器 ( stream editor ),流编辑器会在编辑器处理数据之前基于预先提供的一组数据规则来编辑数据流。根据命令来处理数据,这些命令要么从命令行输入,要么存储在一个命令文本文件中。

sed 编辑器处理事务:

  1. 一次从输入中读取一行数据。
  2. 根据提供的编辑器命令匹配数据。
  3. 按照命令修改流中的数据。
  4. 将新的数据输出到 STDOUT

sed 将所有命令与一行数据匹配完毕后,读取下一行数据并重复该过程,处理完所有数据,终止。

# 基本格式

格式: sed options script file

为了更好理解,举个例子。

先创建一个数据文件 data ,其中包含 6 行 'cat'。然后我们希望将 'cat' 替换为 'dog'。

cyan@cyan-virtual-machine:~/Templates$ sed 's/cat/dog/' data
dog
dog
dog
dog
dog
dog
# ‘s/cat/dog/’是后者替换前者
# 此次命令没有使用选项,scirpt 就是's/cat/dog' file 就是 data

sed 命令非常快。处理一行显示一行,但是 sed 并不会修改文件原始数据,只是将结果传给 STDOUT 而已,当然,也可以重定向。

sed 's/cat/big cat/' data > result

sed 可以执行多个命令,使用 -e 选项,多个命令分号隔开,并且分号紧靠上一个命令

sed -e 's/brown/green/; s/dog/cat/' data
# 或者是这样,shell 一旦发现封尾的单引号,就会执行命令
sed -e '
> s/brown/green
> s/fox/cat
> ' data

如果要执行的命令太多,可以放在文件中,使用 -f 选项,该选项会在处理输入时,将文件中指定的命令添加到已有的命令中。

sed -f script.sed data
# 为避免混淆,一般将 sed 的命令文件后缀写为.sed
# 例子
cyan@cyan-virtual-machine:~/Templates$ cat command.sed
s/cat/dog/
s/Jack/Mark/
cyan@cyan-virtual-machine:~/Templates$ cat data
cat Jack
cat Jack
cat Jack
cat Jack
cat Jack
cyan@cyan-virtual-machine:~/Templates$ sed -f command.sed data
dog Mark
dog Mark
dog Mark
dog Mark
dog Mark

关于 s 替换命令,还有其他选项

  • sed 's/cat/dog/' data 只会替换每行第一处 cat 。如果想在第 n 处替换, s/cat/dog/n'
  • g 选项,所有匹配到的标记都会被替换。
  • p 选项,文本原先行内容替换后要打印出来: sed -n 's/cat/dog/p' data , 一般和 -n 配合使用, -n 禁止 sed 输出,配合 p 使用,就只会打印含有标记的文本。
  • w file , 将替换的结果写到文件中: sed 's/cat/dog/w aim.txt' data
cyan@cyan-virtual-machine:~/Templates$ sed 's/cat/dog/w test_data' data
dog Jack
dog Jack
dog Jack
dog Jack
dog Jack
cyan@cyan-virtual-machine:~/Templates$ cat test_data
dog Jack
dog Jack
dog Jack
dog Jack
dog Jack

有时候, / 使用起来比较麻烦,可以使用 ! 来代替: s!cat!dog!

# 使用地址

可以指定命令对某些特定的行数进行处理, sed 编辑器的行寻址有两种形式:

  • 数字表示行区间
# 1. 对单行指定修改
sed '2s/cat/dog/' data
# 2. 对行区间进行执行修改
sed '2,5s/cat/dog' data # 2~5 行被修改
# 3. 美元符号 $
sed '2,$s/cat/dog/' data   # 对 2 行及以下的数据执行命令
  • 文本模式来过滤出行, /pattern/command 。比如修改用户 cyan 的默认 shell 。匹配模式十分类似 grep ,固定文本作用有限,最常用的是使用正则表达式。 匹配模式十分类似 grep,固定文本作用有限,最常用的是使用正则表达式。
$ grep cyan /etc/passwd
cyan:x:1000:1000:cyan,,,:/home/cyan:/bin/bash
$sed '/cyan/s/bash/csh/' /etc/psswd
  • 当有多条命令时候。
address { #多条命令时,需要用 {} 来限定作用域
        command1
        command2
}
# 例
sed '2{
> commands    
}' data.txt

# 删除与修改

sed 可以替换,也可以删除,使用 d 命令: sed '3d' data ,和行寻址一起使用发挥最大作用。输出到 STDOUT 的结果是删除指定行之后的剩余文本。

如果我希望删除某个区间的文本(使用文本匹配)

cat data
num start
num 2
num 3
num end
num 4
num start again
kk
nn
# 执行命令:sed '/start/,/end/d' data
# 结果 num 4

一开始遇到 start ,打开删除模式,持续删除,直到遇到 end ,关闭删除模式 (没遇到就一直删除)。再次遇到 start 时 ( num start again ),打开删除模式,并持续删除。

sed 编辑器是不会修改原始文件的,修改的只是从 sed 编辑器的输出中消失了。

至于修改行的内容,之前的 s 命令需要匹配,而 c 命令是直接修改整行内容, c--change

sed '1c\this is changed line' data.txt
sed '/num 1/c\this is changed line' data.txt
sed '2,3c\this is changed line' data.txt
# c 命令之后用的是反斜杠 \, 并且没有封尾,也就是 line 后没有 \
# 第三个使用区间修改行,并不是将区间的每一行都修改为指定行,而是用该指定行替换数据流中区间的所有文本

# 插入和附加文本

插入 insert--i : 会在指定行增加一个行, echo "test line 2" | sed 'i\test line 1'
附加 append--a : 会在指定行增加一个行, echo "test line 2" | sed 'a\test line 1'

如果想要附加到行尾,只需要使用美元符号: sed '$a\new line' data个人觉得美元符号是数据流最后一行的意思
要插入(附加)多行数据,需要在每行之间使用 \

sed '1i\
> line 1\
> line 2
> ' data

# 转换命令

y 命令是唯一可以处理单个字符的 sed 编辑器命令 [address]y/inchars/outchars/

sed 'y/123/789/' data

inchars 的第一个字符会被映射为 outchars 的第一个字符,以此类推,直到处理完指定字符。其中,如果两者长度不一样,会报错。
转换命令是全局命令,无法限定只转换在特定地方出现的字符 (以行为单位),也就是一行所有的字符都要被转换

# 打印命令

之前使用 s 替换命令时,配合 -np 选项,打印出修改的行,还有些命令也能打印数据流信息。

= 命令打印行号行号由数据流中的换行符来决定,每出现一个换行符,sed 编辑器就认为一行结束了。

sed '=' data

l 命令可以打印出数据流中的文本和不可打印的 ASCII 字符 (一般是标准 C 风格或八进制), l 就是 list

sed -n 'l' data

# 处理文件

  • 写入文件: [address]w filename
sed -n '1,2w aim.txt' data
 # 在 aim.txt 追加
  • 读取文件: [address]r filename 。 允许将一个独立文件中的数据插入到数据流中,插入到指定行后。
sed '3r sources.txt' data