Linux-Sed命令
背景
之前讲到文本编辑的时候,讲到Vim编辑器,在shell命令行下有很多类编辑器,比如:vi、emacs、vim、nano
等,它们作为一个独立的软件包,对我们还是很友好的,但是当我们需要对文本进行自动化处理的时候,它们就无法很好的使用了,因此就引入了流编辑器的概念,其中之一便是sed
命令
内容
入门
作为流编辑器,它有如下几个特点:
- 每次从输入中读取一行
- 根据提供的编辑器命令匹配数据,并根据命令修改流中的数据
- 将新的数据输出到
STDOUT
中,而不是回写至文件中,除非人为设定
它的格式如下:
1 | option:指定参数 |
比如:
1 | 如果有多个命令,则之间用;隔开 |
如果含有大量的sed命令,则可以单独创建sed命令文件,然后使用-f
引入该文件:
1 | 建议将sed命令文件加后缀.sed |
sed
和其它常规命令一样,它也有众多的参数,参数的不同意味着不同的功能。but,在sed
中,除了参数,还有替换标记中的一些指令有其特殊的含义。比如刚刚讲述的s
就是替换文本的标识,它完整的格式是:
1 | s/pattern/replacement/flags |
对于替换标记中的间隔符号,除了传统的/
以外,也可以指定其它的字符,如!
:
1 | 如果替换内容中有/,则需要用\进行转移 |
上述的方式会将替换的指令作用于文本中所有的行,如果只是想作用于文本中指定的行,则可以借助行寻址
,有两种方式:通过数字寻址、文本模式寻址
。通过数字寻址的方式如下:
1 | 格式 |
如果需要对同一行执行多条命令,则需要借助于{}
:
1 | sed -e "2,5{ |
通过文本寻址
的方式如下:
1 | pattern会匹配到符合条件的行上,它也支持通过正则进行匹配 |
除了s
替换指令外,还有删除指令d
:
1 | 格式: |
还有增加的命令:i、a
1 | 格式: |
如果需要一次性在指定位置插入多行数据,则在每行内容后追加\n
换行符,如下:
1 | sed -e "3i\nbaqi\nniubi\nshuai" file |
然后就是修改行的命令:c
1 | 格式: |
但是如果你想用一行内容替换掉多行内容则不行,sed
会依次用给定的行替换选区内的行,替换完了则剩余行的内容不变。
另外还有一个转换字符的命令:y
,它会替换掉指定的单个字符,并且它是一个全局命令,这意味着无法指定选区,它作用于整个文档:
1 | 运作原理:它使用inchars的第一个字符替换为outchars的第一个字符,以此类推。 |
接着就是打印内容的命令:p
、=
、l
,其中p
用于输出内容,=
专注于打印行号,l
可以打印文本中肉眼不可见字符:
1 | 格式 |
在sed
中,还可以将指定的内容保存到新的文件中,这个需要借助于命令:w
1 | filename是文件的路径,相对、绝对都可以 |
同样还可以在一个文件的文件流中读取其他文件的内容,这个需要借助于命令:r
1 | filename是文件的路径,相对、绝对都可以 |
高级
入门中,讲述的内容都是针对单行内容的,可是如果我们遇到了需要处理跨行内容的时候,入门知识就无法完全适用了,这个时候就会讲到跨行命令,比如,如果我们需要清理定位元素下一行的内容,这个时候就需要借助命令:n
1 | n:表示处理定位元素的下一行,定位的行不修改 |
假如我们需要对两个连续行的内容合并在一起处理时,此时需要借助命令:N
1 | N:表示将相邻的两行元素合并在一起进行处理,注意换行符还是存在的 |
关于N
,需要注意,虽然将两行当成一行处理,但是跨行中的换行符还是存在的\n
,同时,它是在匹配address后开始依次将连续的两行当成一行进行处理
,比如将1、2当成一个对象,再将3、4当成一个对象,不存在将2、3再组成一个对象处理。
之前讲过删除行的命令d
,它只能作用于选择域内,如果我们希望删除定位位置的上一行,此时则需要借助命令:D
1 | D:删除模式空间中的第一行 |
关于D
,它作用的是一个模式空间,所以一般跟N
协作,此外它只会删除匹配的模式空间的第一行,即便匹配到的内容是第二行也不行。
然后就是和打印命令p
相对应的P
,它也是只打印模式空间中的第一行内容,即使匹配的内容是模式空间中的第二行也不行
1 | P:打印模式空间中的第一行 |
说到此处,就聊到了sed文本流工作的方式:逐行读取并运行
,所以如果用p、P
直接打印的话,它是读一行打印一行的。
上面提及的模式空间
其实就是我们操作的每一个文本行对象,sed
每开始读取一行数据的时候,就会将读取的内容放到模式空间
中(理解为工作空间),与此相对应的还有保持空间
的概念,保持空间
可以理解为Windows下的剪贴版,用于保存内容的,起始情况下,保持空间中存有一个空行
。在sed中,如果我们需要将模式空间
的内容添加到保存空间
,则需要用到指令:h、H
1 | h:表示将模式空间的内容提取到保存空间 |
上面的内容不是看得有点懵,默认情况下,sed
是读取一行内容就处理一行内容,如果不指定-n
选项,则sed
会根据情况,不处理的行会直接输出,然后执行处理的命令,并输出处理后的结果;如果指定了-n
选项,则sed
的输出内容就完全取决于用户在什么位置p
,否则就算是内容进行了修改,STDOUT
也不会有任何的输出。
带着这样的理解,再回头看上面的命令:
1 | sed -n -e "/first/{h;n;p;g;p}" file |
记住一点:p只能打印模式空间的内容
,同样,如果需要将保持空间
的内容复制到模式空间
的话,则可以借助命令:g、G
,
1 | g:将保持空间内容复制到模式空间 |
还有另外一个指令:x
,用户交换保持空间
和模式空间
中的内容
1 | 格式和上面的一行 |
不过Linux下也已经为我们提供了文本反转输出的命令:tac
1 | tac file |
有时候希望某些命令不会作用于指定的区域,则可以借助命令:!
,但是一定要注意:包裹修改命令的部分一定要是单引号,否则shell会以为我们想要调用历史命令
1 | 表示除了第一行以外,其它行都执行打印命令 |
同样还可以借助于分支命令:b
,实现对指定区域内的内容执行部分命令
1 | label:指示跳转的位置,如果没有,则表示跳转到命令的结束位置 |
如果将label
的位置置于了跳转之前,则还可以形成一个循环的效果
1 | wudashuai@localhost: sed -n -e " |
此外sed还提供了测试(test)命令:t
,它就像程序中的if判断语句一样,它会根据替换命令的执行结果来决定是否跳转
,如果替换成功,则不执行跳转,继续执行之后的操作;反之则可以执行跳转。
1 | 规则和b一样 |
同时,sed
中的替换命令s
支持分组引用,比如对匹配内容的引用就可以借助于命令:&
1 | 它就会将正则匹配的内容外部追加" |
同样也可以采用分组,然后通过\num
的方式引用,但是需要注意,分组的括号一定要用\进行转义,否则会被shell当成字符处理
:
1 | 会将第一个框号的内容与第二个括号的内容进行互换 |
之前讲过分支命令b
,其实它就像循环,对应的sed
还提供了一个跳出循环的命令:q
1 | 格式: |
剩下的,就是无尽的基操了!去吧,少年,经历社会的毒打吧!!!