Linux sed
在Linux中,sed是Stream Editor(流式编辑器)的缩写,所谓的流式编辑器就是不像vim这种编辑器一样一次性将所有文件内容读取到内存中。而是将文本内容一行一行读取到内存中进行处理。读取一行就处理一行,直到全部处理完成;
sed这个工具一般在shell脚本里面使用比较多,用来非交互式修改文件内容。
工作原理
-
运行sed命令后,操作系统就启动了一个sed进程,会给这个sed进程分配内存空间,这个内存空间分为两部分。一部分叫做模式空间,另外一部分叫做保持空间。
-
编辑文件的时候,会将硬盘中的文件内容一行行读到内存(模式空间),然后进行处理后输出。
使用格式
sed [option] '处理方法' /path
-
处理方法说明:处理方法 = 定位 + 操作
-
定位:匹配到指定的内容(对哪行内容作什么样的处理)
-
操作:具体做什么处理,例如删除、修改、替换等。
例如:
sed '' 1.txt
# 没有指定处理方法,会将文件的内容原样输出到屏幕;
常用选项
-
-r或-E: 表示支持扩展正则,类似于grep的 -E 选项,sed默认只支持基本正则
-
-i:表示对文件进行修改,流出到屏幕的内容会流入到屏幕里面去。这样就实现了文件的修改
-
-n:表示取消模式空间的默认输出,模式空间默认就是输出到屏幕上的
-
-e:可以对指定内容作多次处理,也可以将多个处理之间使用分号(;)分隔,效果等通过-e选项;
处理方法
上面我们说了sed的处理方法由两部分组成,定位和操作,定位表示要对那行内容进行处理,操作表示要对定位到的内容做什么样的处理。
数据定位方式
行号定位
特点:直接指定行号,通过行号来定位指定的行,从而进行处理
匹配单行:例如:sed '6CMD' /path 表示匹配到第6行时,就使用CMD命令进行处理。
匹配范围:例如:sed '6,9CMD' /path 表示匹配6-9行时,就使用CMD命令进行处理
正则定位
特点:通过正则匹配到对应的行
格式:'/正则表达式/CMD'
例如:sed '/tom/命令' /path 表示匹配含有tom的行,使用CMD命令进行处理
说明:两个斜杠的作用就是起分隔的效果,当然也可以换成其它符号。例如:ed '@.*@命令' /path
两者结合定位
例如:sed '3,/tom$/' 表示从第三行开始,到以tom结尾的行的这个范围;
数据处理方式
用于对定位到的指定内容做相关操作;
-
p 输出指定的行内容到屏幕
-
s 用于实现替换操作,语法: 's/需要替换的/替换后的'
-
c 替换某一行的内容
-
d 匹配到指定行,就将该行删除,不输出到屏幕
-
a 再某些行后面加内容
-
i 再某些行前面加内容
-
g 全部替换,一般结合s命令就行使用。
范例
输出文本文件中第二行的内容
sed -n '2p' 1.txt
# 加-n就是取消默认的输出,默认会把所有内容都输出到屏幕上
输出以root开头的字符的行到屏幕上
sed -n '/^root/p' 1.txt
输出第三行到第六行的内容
sed -n '3,6p' /etc/passwd
输出奇数行内容
sed -n '1~2p' /etc/passwd
# 从1开始,每次的增量都是2 即 1 3 5 7 9 ...
包含nologin的内容都删除,不输出到屏幕
sed '/nologin$/d' passwd
# 源文件不会发生改变的
把每行的第一个nologin替换为login
sed 's/nologin/login/' 1.txt
# 不指定范围,就是全部都匹配
# 没有加g参数,只会替换每行中第一个匹配到的指定字符,如果一行有多个相同的内容,只会替换最左边的一个。如果向全部替换,需要加g命令
将每行中的每个nologin替换为login
sed 's/nologin/login/g' 1.txt
将指定行内容全部替换
sed -i '/^#set_var EASYRSA_CA_EXPIRE/c\set_var EASYRSA_CA_EXPIRE 36500' /etc/openvpn/rsa-server/vars
# /^#set_var EASYRSA_CA_EXPIRE/表示通过正则匹配以xxx开头的行
# c\set_var EASYRSA_CA_EXPIRE 36500' 表示替换后的内容
# /etc/openvpn/rsa-server/vars是文件名
# 转义字符的作用是确保 c\xxxxxx被正确解释为替换内容,而不是被解释为其他特殊含义的字符。
c操作和s操作的区别:
c操作是将匹配到的行进行整体替换,s操作是将匹配到的内容进行替换更改。
取匹配到的内容
通过 & 符号表示的就是获取前面匹配到的内容,当然也可以使用扩展正则表达式的小括号,结合\n来获取指定括号中的内容。
一般使用后者就行了。这种方法叫作正则表达式的分组(后项引用),即通过小括号实现分组,后面要表示第几个分组的内容就用 \num(第几个小括号里面的内容,从而实现把一个文件的一行切成多块,保留其中所需部分。
将非#开头的行加#
sed -rn 's/^[^#](.*)/#\1/p' /etc/fstab
selinux配置修改
sed -r -i '/^SELINUX=/s/(SELINUX=).*/\1disabled/' /etc/selinux/config
获取网卡ip地址
ifconfig eth0 | sed -rn '2s/(.*inet )([0-9].*)(netmask.*)/\2/p'
10.0.0.22
在行尾的数字后面加 .change
sed 's/[0-9]$/&.change/'
使用变量
正常情况下sed的命令格式是 sed [option] '处理方法' filename 处理方法部分是用单引号引起来的,就是怕shell把这里面的字符当成通配符给解释了。这样也就造成了一个问题,在里面用shell的变量,变量就没法替换为具体的值。
解决方法: 使用双引号来将处理方法括起来,但是如果里面有一些特殊字符,需要使用转义字符 \ 进行转义,不然会被shell当成通配符解释。
shell一般会解释以下一些字符:
这些字符在shell里面具有特殊的意义,所以如果sed使用的时候,没有才取强引用,需要使用转义字符来进行转义才行。
$ --- 变量引用,
反引号 --- 命令替换
| --- 管道符
& --- 后台运行命令
*、?、[ ] --- 通配符
{} --- 扩展符
>,<,<<,>> --- 重定向
; --- 命令分隔符
() --- 组合命令