sed

sed 可以实现不打开文件就能编辑文件内容的操作,有点⑥,而且有点复杂,看了好多文章,总算弄懂了点,可能是别人写的不好,哈哈。

同时,还可以拿来做格式化文本

sed :stream editor 流编辑器,它是按行来执行的,一次执行一行,把要处理的行储存在缓冲区中(pattern space),执行完后,输出到屏幕,直到所有行处理完。这也就是说如果不加参数限制,它是不会真正对文件做修改的,get?

格式

1
sed [OPTION]... {script-only-if-no-other-script} [input-file]...

各部分的参数

OPTION常用选项:

1
2
3
4
5
-n	#silent模式,sed默认会将所有数据都输出到屏幕,但是加上-n后,只会输出匹配到的行,需要结合p参数,实现打印。
-e #expression表达式,指定sed的命令,默认就有这个,其真正作用是可以提供多个不同的命令。
-i #in-place替代,这个参数才是真正将修改直接写入文件的操作,所以修改文件内容必须要它啊。
-f #file,读取写有命令的文件,作用是可以写好一个命令文件后实现批量处理。
-r #regexp-extended,支持扩展正则表达式。

SCRIPT命令动作:

命令部分都是通过单引号括起来的;命令有两种方式:一种就是sed自身支持的写法,一种是使用正则表达式

1
2
3
4
5
6
7
8
a	#append text,新增行,在匹配到的行后
i #insert text,插入行,在匹配到的行前
d #delete pattern space,删除匹配到的行
s #substitute regex,替换,需要使用正则表达式
p #print the current pattern space,打印匹配到的行
c #replace line with text,替换匹配行的内容
r #append contents of file,相当于a参数,只不过这个是读取的文件
w #write pattern space to file,将匹配到的内容输出到另外的文件,不动源文件,等于另存为。

INPUT-FILE:

需要操作的文件

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
#下面所有操作基于的文件
nl test.sh

1 #!/bin/zsh

2 j=1
3 cd ~
4 for i in `ls`
5 do
6 a[$j]=$i
7 ((j++))
8 done
9 echo ${a[*]}
新增
1
2
3
4
5
6
7
8
9
10
#举例:在第四行后添加”四叶草“
不使用正则表达式
sed '4a 四叶草' test.sh #最好在a与后面文字间留空格,虽然不留空格也行


#在第四行和第六行后添加”四叶草“
sed '/[4,6]/a 四叶草' test.sh

#在第四行第五行第六行后添加”四叶草“
sed '4,6a 四叶草' test.sh
1
2
#举例:在有do的前一行添加”四叶草“
sed '/do/i 四叶草' test.sh
删除
1
2
#举例:删除以5开头的行
sed ‘/^5/d' test.sh
1
2
3
4
5
6
7
8
9
1	#!/bin/zsh

2 j=1
3 cd ~
4 for i in `ls`
6 a[$j]=$i
7 ((j++))
8 done
9 echo ${a[*]}
替换
1
2
#举例:将2到最后一行所有i替换为jc
sed '2,$s/i/jc/g' test.sh
1
2
3
4
5
6
7
8
9
10
1	#!/bin/zsh

2 j=1
3 cd ~
4 for jc jcn `ls`
5 do
6 a[$j]=$jc
7 ((j++))
8 done
9 echo ${a[*]}
取指定行
1
2
#举例:打印第一行内容
sed -n '1p' test.sh
1
1	#!/bin/zsh
1
2
#举例:打印5到最后一行内容
sed -n '5,$p' test.sh
1
2
3
4
5
6
4	for i in `ls`
5 do
6 a[$j]=$i
7 ((j++))
8 done
9 echo ${a[*]}
替换匹配行
1
2
#将有do的行都替换为“四叶草”
sed '/do/c 四叶草' test.sh
1
2
3
4
5
6
7
8
9
10
1	#!/bin/zsh

2 j=1
3 cd ~
4 for i in `ls`
四叶草
6 a[$j]=$i
7 ((j++))
四叶草
9 echo ${a[*]}
读取文件内容
1
2
3
4
5
#在所有的j后面添加com.txt中的内容
cat com.txt
滑小稽你最近有点皮是不是

sed '/j/r com.txt' test.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
1	#!/bin/zsh

2 j=1
滑小稽你最近有点皮是不是
3 cd ~
4 for i in `ls`
5 do
6 a[$j]=$i
滑小稽你最近有点皮是不是
7 ((j++))
滑小稽你最近有点皮是不是
8 done
9 echo ${a[*]}
写入文件
1
2
#将5到7行内容写入到file.txt中
sed '5,7w file.txt' test.sh
执行多个操作
1
2
#将j换成jjjjjj,将i换成iiiiiii
sed -e 's/j/jjjjjj/' -e 's/i/iiiiiii/' test.sh
1
2
3
4
5
6
7
8
9
10
1	#!/biiiiiiin/zsh

2 jjjjjj=1
3 cd ~
4 for iiiiiii in `ls`
5 do
6 a[$jjjjjj]=$iiiiiii
7 ((jjjjjj++))
8 done
9 echo ${a[*]}
直接修改文件
1
sed -i '1i 这是直接修改的' test.sh
1
2
3
4
5
6
7
8
9
10
11
这是直接修改的
1 #!/bin/zsh

2 j=1
3 cd ~
4 for i in `ls`
5 do
6 a[$j]=$i
7 ((j++))
8 done
9 echo ${a[*]}

sed模式空间pattern space和暂存空间hold space的使用:

sed有两个内存空间用来存储数据,大部分情况下,我们只用到了pattern space。读取到的内容就会进入pattern space,然后进行操作(增,删,查,改)。除非手动调用hold space,否则不会使用到它。

1
2
3
4
5
6
7
8
9
10

h:pattern space > hold space (把模式空间中的内容覆盖至保持空间中)
H:pattern space >> hold space (把模式空间中的内容追加至保持空间中)
g:hold space > pattern space (从保持空间取出数据覆盖至模式空间)
G:hold space>> pattern space(从保持空间取出内容追加至模式空间)
x:pattern space <> hold space (把模式空间中的内容与保持空间中的内容进行互换)
n:读取匹配到的行的下一行覆盖 至模式空间
N:读取匹配到的行的下一行追加 至模式空间
d:删除模式空间中的行
D:删除 当前模式空间开端至\n 的内容(不再传 至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed
  • 利用读取的下一行,来进行奇数与偶数行的选取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    --- ~ » seq 10 | sed 'n;d'  
    1
    3
    5
    7
    9
    --- ~ » seq 10 | sed -n 'n;p'
    2
    4
    6
    8
    10
  • 使用hold space来打印空行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    --- ~ » seq 3 | sed 'G'
    1

    2

    3

    # 先删除所有空行,再添加空行,保证只有一个空行
    --- ~ » seq 3 | sed '/^$/d;G'
    1

    2

    3
  • 利用pattern space和hold space数据转换来达到倒序的效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    --- ~ » seq 10 | sed '1!G;h;$!d'
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1