linux中玩转sed技巧分享

sed
命令应用广泛,使用简单,是快速文本处理的利器。它其实没多少技巧,背诵、使用是最合适的学习渠道,属于硬技能。但它又很复杂,因为高级功能太多。本篇不去关注sed的高级功能,仅对常用的一些操作,进行说明。
sed使用
sed编辑器被称作流编辑器,它和vim这种的交互式文本编辑器不同,是根据命令来处理数据流中的数据。会执行下列操作:
- 一次从输入中读取一行数据(重复该操作直到全部行被读取完)
- 根据编辑器命令匹配数据
- 按照命令修改数据流中的数据
- 将新数据输出到STDOUT(标准输出)
其中sed命令的可以从命令行中输入,也可以从一个命令文件中读取。
sed命令的格式如下:
1 |
|
替换命令s
s
命令会用斜线间指定的第二个文本字符串来替换第一个文本字符串模式。
1.用big test替换了test。
1 | $ echo "This is a test" | sed 's/test/big test/' |
2.用cat替换整个文件中的dog
示例文件:
1 | $ cat data1.txt |
使用sed命令进行替换:
1 | $ sed 's/dog/cat/' data1.txt |
🌟 重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。
3.在命令行使用多个编辑器命令
1 | $ sed -e 's/brown/green/; s/dog/cat/' data1.txt |
4.从文件中读取编辑器命令
如果有大量要处理的sed命令,那么将它们放进一个单独的文件中通常会更方便一些。
可以在sed命令中用-f
选项来指定文件。
示例sed编辑器脚本文件
1 | $ cat script1.sed |
执行sed编辑器脚本文件,按照脚本文件替换。
1 | $ sed -f script1.sed data1.txt |
更多替换选项
替换标记
替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处。要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记(substitution flag)。
替换标记会在替换命令字符串之后设置。格式如下:
1 | s/pattern/replacement/flags |
有4种可用的替换标记:
- 数字,表明新文本将替换第几处模式匹配的地方;
- g,表明新文本将会替换所有匹配的文本;
- p,表明原先行的内容要打印出来;
- w file,将替换的结果写到文件中。
示例如下:
1 | # sed编辑器只替换每行中第二次出现的匹配模式 |
🌟 sed并没有对文件内容进行改变,因此如果要写回文件,可以使用重定向。
1.通过重定向写入新文件,如:
1 | $ sed "s/dog/cat/g" data1.txt > data1new.txt |
或者使用-i
参数直接修改文件内容,如下:
1 | $ sed -i "s/dog/cat/g" data1.txt |
2.在每一行前面添加内容
1 | $ sed 's/^/#/g' data1.txt |
3.在每一行最后添加内容
1 | $ sed 's/$/---/g' data1.txt |
顺便介绍一下正则表达式的一些最基本的东西:
^
表示一行的开头。如:/^#/
以#开头的匹配。$
表示一行的结尾。如:/}$/
以}结尾的匹配。<
表示词首。 如:<abc
表示以 abc 为首的詞。>
表示词尾。 如:abc>
表示以 abc 結尾的詞。.
通配符,表示几乎任意字符,除了换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号 … 中的每个点,此处省略了无数个字(什么情况都可能发生)。?
表示某个字符出现了0次或1次。*
表示某个字符出现了0次或多次。+
表示某个字符出现了1次或多次。[ ]
字符集合。 如:[abc]
表示匹配a或b或c,还有[a-zA-Z]
表示匹配所有的26个字符。如果其中有^表示反,如[^a]
表示非a的字符。还有[0-9]
匹配括号中的任何一个字符。{m}
前面的匹配重复m次,{m,n}
前面的匹配重复m到n次
💡 强大到无往不利的正则表达式简单示例,比如去除下面html中的tags:
1 | <b>This</b> is what <span style="text-decoration: underline;">I</span> meant. Understand? |
sed命令实现:
1 | # 如果你这样搞的话,就会有问题,贪婪模式,匹配(<)到(>)之间的所有内容 |
💡 其他有趣示例
1.输出长度不小于50个字符的行
1 | $ sed -n '/^.{50}/p' |
2.统计文件中有每个单词出现了多少次
1 | $ sed 's/ /n/g' file | sort | uniq -c |
3.查找目录中的py文件,删掉所有行级注释
1 | $ find ./ -name "*.py" | xargs sed -i.bak '/^[ ]*#/d' |
4.查看第5-7行和10-13行
1 | $ sed -n -e '5,7p' -e '10,13p' file |
5.仅输出ip地址
1 | $ ip route show | sed -n '/src/p' | sed -e 's/ */ /g' | cut -d' ' -f9 |
使用地址
默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须用行寻址(line addressing)。
数字方式寻址
sed编辑器会将文本流中的第一行编号为1,然后继续按顺序为接下来的行分配行号。
1.只修改第二行的数据
1 | $ sed '2s/dog/cat/' data1.txt |
2.修改第二行和第三行,使用行地址区间
1 | $ sed '2,3s/dog/cat/' data1.txt |
3.也可以匹配从文本中某行开始到结束的所有行
1 | $ sed '2,$s/dog/cat/' data1.txt |
使用文本过滤器
sed编辑器允许指定文本模式来过滤出命令要作用的行。格式如下:
1 | /pattern/command |
必须用正斜线将要指定的pattern封起来。sed编辑器会将该命令作用到包含指定文本模式的行上。
举个栗子🌰来说明一下吧,在/etc/passwd
中只修改用户Samantha的默认shell,如下:
1 | $ grep Samantha /etc/passwd |
删除行
使用删除命令d对文本进行删除操作。
1 | # 删除所有文本 |
插入、附加文本
1.插入命令i
在指定行前增加新行
2.附加命令a
在指定行后增加新行
1 | # 追加 |
修改行
使用c
命令来修改一行数据
1 | # 修改第三行文本 |
转换命令
命令格式sed 'y/inchar/outchar'
将inchar中的字符一一对应地转换成outchar的字符
1 | $ echo "This 1 is a test of 1 try." | sed 'y/123/456/' |
💡 如你在输出中看到的,inchars模式中指定字符的每个实例都会被替换成outchars模式中
相同位置的那个字符。
打印命令
1.打印数据文本
1 | $ echo "this is a test" | sed 'p' |
2.打印包含匹配文本模式的行
1 | $ cat data6.txt |
3.快速打印数据流中的某些行
1 | $ sed -n '2,3p' data6.txt |
4.从第一行打印匹配3成功的那一行
1 | $ sed -n '1,/3/p' data6.txt |