简谈linux文本处理-sed
文本处理能力是Linux强大优势之一,其中grep,sed和awk被称为Linux文本处理三板斧。grep 主要配合正则表达是来查找内容,在之前的文章里有提及,这篇文章则浅谈sed使用。
sed
sed工作流:读取$\to$执行命令$\to$显示。默认情况,所有的命令都会一个叫做在模式空间(pattern buffer)的缓冲区进行。因此不会改变原始输入文件的内容。
语法规则
sed即支持在命令行中用单引号输入执行命令,也支持执行含有sed命令的文件。使用方式如下:
sed [‐n] [‐e] 'command(s)' files
sed [‐n] ‐f script files
选项
sed 后面首先需要跟参数,支持的参数有:
选项与参数:
-n :禁止显示所有输入内容,只显示经过sed处理的行(常用)
-e :直接在命令列模式上进行 sed 的动作编辑,接要执行的一个或者多个命令
-f :执行含有sed 动作的文件
-r :sed 的动作支持的扩展正则(默认基础正则)
-i :直接修改读取的文件内容,不输出。
作用区域
默认情况下,sed命令会作用于文本数据的所有行。如果只想作用于某些行时,则需要使用在命令通过行号或者文本过滤的方式前指明作用区域。
行号
使用数字行号时,类似于R中的向量子集提取。单独数字表示某一行,逗号分割指示行范围,另外m,+n
表示从m行开始向下n行,m~n
表示从m行开始的每n行。
例如sed ‐n '2~2 p' test.txt
输出偶数行,sed ‐n '1~2 p' test.txt
输出奇数行内容。
文本过滤
'/pattern/ command'
可以只在包含pattern 的行中执行命令。如sed ‐n '/hello/ p' test.txt
只会打印出包含hello的行。sed ‐n '/hello/, /world/ p' test.txt
打印两者之间的所有行。
特殊情况下也可以将文本过滤和行号结合使用,sed ‐n '/hello/,+5 p' test.txt
打印第一次出现hello的下面5行
命令
p 复制
复制模式空间中的内容,如果不和-n
参数连用,每一行都会在屏幕输出两次,一行正常输出一行复制,结合-n
参数后就可以打印需要的内容。
d 删除
没什么可以说的,支持按照行号或者匹配来删除。
i 插入
有的时候一个结果文件没有header,使用sed 可以轻松完成。在匹配位置之前插入内容。
sed '1i name\tlength\foldchange' test.txt
a 追加
和插入命令的区别在于在匹配位置后一行插入内容,,如果想在末尾插入一行信息时将$作为地址。
sed '$a auther:zhaofei' test.txt
c 行替换
有了行的删除插入和追加自然也就会有行替换。
sed '$c auther:zhaofei' test.txt
y 字符转换
sed中的y命令可以实现一一映射的字符替换(注意和s命令的区别)。
[address]y/inchars/outchars/
# inchars中的第一个字符会被转换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符
# 直持续到处理完指定字符。如果inchars和outchars的长度不同会报错
l 输出隐藏字符
类似与cat -A,但是显示隐藏字符形式不同。
w 写入新文件
增强版的cp,只复制自己想要的东西,也可以将一个文件按不同的筛选条件分开保存。
sed -n -e '/a/ w a.txt' -e '1,10 w b.txt' test.txt
sed '1,10d;w new.txt' test.txt
r 读取文件
如果现在a文件的某个地方插入b文件,如在第三行插入
sed '3r b.txt' a.txt
e 执行外部命令
首先要区别于参数-e,这个e是在''里面的命令
sed 'e echo "hello"' test.txt
i 反向执行
在命令前加!反向执行命令
sed '/hello/!d' test.txt
#效果和下面的命令一致
sed -n '/hello/p' test.txt
n 匹配行下移一行操作
提前读取当前行的下一行内容,并且覆盖当前模式空间中的行
seq 5 |sed '3{n;d}'
# 首先匹配到第三行,然后移动到第四行进行删除
# 所及结果是
1
2
3
5
seq 5 |sed 'n;d' #效果类似与输出奇数行
seq 5 |sed -n 'n;p' #效果类似与输出偶数行
= 打印行号
sed '/hello/!d;=' test.txt
s 替换
通用写法[address1[,address2]]s/pattern/replacement/[flags]
这里pattern部分支持正则匹配,flags包括n(替换第n个匹配项),g(全局替换),p(输出改变的行,结合-n),i(忽略大小写匹配),w(保存改变的行到新文件)。
如果要替换的的内容包括了/
,第一种方式是使用\/
进行转义,第二种方法是使用@ | ! ^
作为分隔符。
有时候我们会对文件中的目录进行替换,可以下面的写法
pwd |sed 's@/home/zhaofei@/home/feizhao@'
pwd |sed 's^/home/zhaofei^/home/feizhao^'
pwd |sed 's|/home/zhaofei|/home/feizhao|'
pattern支持各种正则表示法,例如
^ 行首
$ 行尾
. 换行符之外的任意单个字符
? 匹配之前项0次或者一次
+ 匹配1次或者多次
* 匹配0次或者多次
{n} 匹配n次
{n,} 匹配至少n次
{m,n} 至少m,最多n
[] 匹配任意一个
[-] 匹配范围中的一个
[^] 排除字符
| 或者
# posix字符类
[:alnum:] 字母数字
[:alpha:] 字母
[:blank:] 空格制表符
[:digit:] 数字
[:lower:] 小写字母
[:upper:] 大写字母
[:punct:] 标点
[:space:] 所有空白符(换行符和回车)
# 元字符
\s 单个空白
\w 单词
在进行匹配替换时,我们有时候并不想删除匹配的内容,只是希望其以另一种形式和替换内容一起出现。在sed中,特殊字符&
用来存储匹配模式中的内容。
例如
sed 's/[[:digit:]]/number = &/ test.txt
sed 单行命令
# 删除空行
sed '/^$/d'
#每行后增加空行
sed G
# 在每5行后增加一空白行
gsed '0~5G'
# 在匹配式样“regex”的行之后插入一空行
sed '/regex/G'
# 在匹配式样“regex”的行之前和之后各插入一空行
sed '/regex/{x;p;x;G;}'
# 过滤所有的html标签
sed 's/<[^>]*>//g ; /^$/d' html.txt
# cat
sed ''
# head
sed '10 q'
# Dos2unix
sed 's/^M$//'
# Unix2dos
sed 's/$/\r/'
# nl(添加行号)
# sed行号会独占一行
sed = input.file | sed 'N;s/\n/\t/'
# tee
sed ‐n 'p; w new.txt'
# grep
sed ‐n '/pattern/p'
# grep -v
sed ‐n '/pattern/p!'
# 计算行数
sed -n '$='
# 多个内容同时替换
sed 's/a\|b\|c/d/' tmp.txt
# 将每两行连接成一行
sed '$!N;s/\n/ /'
# 如果当前行以等号开头,将当前行并到上一行末尾
# 并以单个空格代替原来行头的“=”
sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'
# 显示包含“AAA”、“BBB”或“CCC”的行(任意次序)
sed '/AAA/!d; /BBB/!d; /CCC/!d'
加入靠谱熊基地,和大家一起交流