介绍

基础介绍

  • sed(Stream Editor),流编辑器。对标准输出或文件逐行进行处理

语法格式

  • 第一种形式:stdout | sed [option] “pattern command”
  • 第二种形式:sed [option] “pattern command” file

处理过程

sed 编辑器逐行处理文件(或输入),并将输出结果发送到屏幕。 sed 的命令就是在 vi和 ed/ex 编辑器中见到的那些。 sed 把当前正在处理的行保存在一个临时缓存区中,这个缓存区称为模式空间或临时缓冲。sed 处理完模式空间中的行后(即在该行上执行 sed 命令后),就把改行发送到屏幕上(除非之前有命令删除这一行或取消打印操作)。 sed 每处理完输入文件的最后一行后, sed 便结束运行。 sed 把每一行都存在临时缓存区中,对这个副本进行编辑,所以不会修改或破坏源文件。

sed选项

选项 含义
-n 只打印模式匹配行
-e 直接在命令行进行sed编辑,默认选项
-f 编辑动作保存在文件中,指定文件执行
-r 支持扩展正则表达式
-i 直接修改文件内容

sed中的pattern详解

pattern用法表

匹配模式 含义
10command 匹配到第10行
10,20command 匹配从第10行开始,到第20行结束
10,+5command 匹配从第10行开始,到第16行结束
/pattern1/command 匹配到pattern1的行
/pattern1/,/pattern2/command 匹配到pattern1的开始行,到匹配到pattern2的结束行
10,/pattern1/command 匹配从第10行开始,到匹配到pattern1的行结束
/pattern1/,10command 匹配到pattern1的行开始,到第10行匹配结束

练习

用法 命令 说明
LineNumber—直接指定行号 sed -n “17p” file 打印file文件的第17行
StartLine,EndLine—指定起始行号和结束行号 sed -n “10,20p” file 打印file文件的10到20行
StartLine,+N—指定起始行号,然后后面N行 sed -n “10,+5p” file 打印file文件中从第10行开始,往后面加5行
/pattern1/—正则表达式匹配的行 sed -n “/^root/p” file 打印file文件中以root开头的行
/pattern1/,/pattern2/—从匹配到pattern1的行开始,到匹配到pattern2的行结束 sed -n “/^ftp/,/^mail/p” file 打印file文件中第一个匹配到以ftp开头的行开始,到第二个匹配到以mail开头的行结束
LineNumber,/pattern1/从指定行号开始匹配,直到匹配到pattern1的行 sed -n “4,/^hdfs/p” file 打印file文件中从第4行开始匹配,直到以hdfs开头的行
/pattern1/,LineNumber—从pattern1匹配的行开始,直到匹配到指定的行数结束 sed -n “/root/,10p” file 打印file文件中匹配root行,直到第10行结束

sed中的编辑命令详解

编辑命令对照表

类别 编辑命令 含义
查询 p 打印
增加 a 行后追加
i 行前追加
r 外部文件读入,行后追加
w 匹配行写入外部文件
删除 d 删除
修改 s/old/new 将行内第一个old替换为new
s/old/new/g 将行内全部的old替换为new
s/old/new/2g 将行内前2个old替换为new
s/old/new/ig 将行内old全部替换为new,忽略大小写
其他编辑命令 = 显示行号

什么是反向引用?

  • &和\1 引用模式匹配到整个串

  • sed “s/1..e/&r/g” file 在file中搜索以1开头,然后跟两个任意字符,以e结尾的字符串

  • sed "s/\(1..e\)/\1r/g" file 和上面实现一样的功能,使用\1代表搜寻到的字符串

    上面两种方式实现了一样的功能,分别使用&和\1引用前面匹配到整个字符串

    两者区别在于&只能表示匹配到的完整字符串,只能引用整个字符串;而\1可以使用()对匹配到的字符串

    例如:如果我们仅想要替换匹配到的字符串的一部分,name必须使用\1这种方式,不能使用&

    查找test.txt文中以1开头,紧接着跟着两个任意字符,再接一个e的字符串。将找到的字符串中开头的

    sed "s/1\(..e\)/L\1/g" test.txt

sed中引用变量时注意事项:

  1. 匹配模式中存在边,则建议使用双引号
  2. sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号

利用sed查询特定内容

查询命令对照表

查询命令 含义
1p 打印1行内容
1,10p 打印1行到10行的内容
1,+5p 打印1行到6行的内容
/pattern1/p 打印每行中匹配到pattern1的行内容
/pattern1/,/pattern2/p 打印匹配到pattern1的行直到匹配到pattern2的所有内容
/pattern1/,10p 打印匹配到pattern1的行到10行的所有行内容
10,/pattern1/p 打印第10行直到匹配到pattern1的所有行内容

练习

打印/etc/passwd中第20行的内容 sed -n ‘20p’ /etc/passwd
打印/etc/passwd中从第8行开始,到第15行结束的内容 sed -n ‘8,15p’ /etc/passwd
打印/etc/passwd中从第8行开始,然后+5行结束的内容 sed -n ‘8,+5p’ /etc/passwd
打印/etc/passwd中开头匹配lvjing字符串的内容 sed -n ‘/^lvjing/p’ /etc/passwd
打印/etc/passwd中开头为root的行开始,到开头为hdfs的行结束的内容 sed -n ‘/^root/,/^hdfs/p’ /etc/passwd
打印/etc/passwd中第8行开始,到含有/sbin/nologin的内容的行结束内容 sed -n ‘8,//sbin/nologin/p’ /etc/passwd
打印/etc/passwd中第一个包含/bin/bash内容的行开始,到第5行结束的内容 sed -n ‘//bin/bash/,5p’ /etc/passwd

脚本练习

需求描述:处理一个类似MySQL配置文件my.cnf的文本,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
[client]
port = 3306
socket = /data/mysqldata/3307/mysql.sock
default-character-set = utf8mb4

[mysqld]
port = 3307
socket = /data/mysqldata/3307/mysql.sock
pid-file = /data/mysqldata/3307/mysql.pid
basedir = /usr/local/mysql-5.7.11
datadir = /data/mysqldata/3307/data
tmpdir = /data/mysqldata/3307/tmp
character_set_server = utf8mb4
collation_server = utf8mb4_bin
user = mysql
log_bin_trust_function_creators = 1     
performance_schema = 0
secure_auth = 1
ft_min_word_len = 1
myisam_recover
explicit_defaults_for_timestamp
event_scheduler
skip-external-locking
skip-name-resolve
bind-address = 127.0.0.1
skip-slave-start
slave_net_timeout = 30
local-infile = 0
back_log = 1024
sql_mode = NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER
NO_AUTO_CREATE_USER                       
key_buffer_size = 32M
max_allowed_packet = 512M
thread_stack = 256K
sort_buffer_size = 16M
read_buffer_size = 16M
join_buffer_size = 16M
read_rnd_buffer_size = 32M
net_buffer_length = 16K
myisam_sort_buffer_size = 128M
bulk_insert_buffer_size = 32M
thread_cache_size = 384
query_cache_size = 0 
query_cache_type = 0  
tmp_table_size = 1024M
max_heap_table_size = 512M
open_files_limit = 10240
max_connections = 2000
max-user-connections = 0
max_connect_errors = 100000
server_id = 100
log_slave_updates = 1
expire-logs-days = 15
max_binlog_size = 512M
auto_increment_offset = 1
auto_increment_increment = 2 
relay_log_info_repository = TABLE
master_info_repository = TABLE
relay_log_recovery = on

# *** innodb setting ***
innodb_buffer_pool_size = 4G
innodb_data_file_path = ibdata1:1G:autoextend 
innodb_flush_log_at_trx_commit = 0
innodb_read_io_threads = 8  
innodb_write_io_threads = 8
innodb_file_format = Barracuda
innodb_open_files = 65536
innodb_purge_threads = 1
innodb_support_xa = FALSE
innodb_log_buffer_size = 256M
innodb_log_file_size = 1G
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 75
innodb_buffer_pool_instances = 4
innodb_io_capacity = 500
innodb_file_per_table = 1
innodb_change_buffering = inserts
innodb_adaptive_flushing = 1
transaction-isolation = READ-COMMITTED
innodb_flush_method = O_DIRECT

[mysqldump]
quick
max_allowed_packet = 512M
net_buffer_length = 16384

[mysql]
auto-rehash


[isamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M



[myisamchk]
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M


[mysqlhotcopy]
interactive-timeout

编写脚本实现以下功能:输出文件有几个段,并且针对每个段可以统计配置参数总个数(需要去除空行和注释)

预期输出结果:

1:client xx
2:mysqld xx
3:mysqldump xx
4:mysql xx
5:isamchk xx
6:myisamchk xx
7:mysqlhotcopy xx

function get_all_segment

function count_items_in_segment #根据段名查找下面的内容,段名间的匹配

获取段的个数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@iZ2ze0gzw63rkie6uwjs74Z lvjing]# grep -E "^\[" my.cnf
[client]
[mysqld]
[mysqldump]
[mysql]
[isamchk]
[myisamchk]
[mysqlhotcopy]
[root@iZ2ze0gzw63rkie6uwjs74Z lvjing]# sed -n '/\[.*\]/p' my.cnf
[client]
[mysqld]
[mysqldump]
[mysql]
[isamchk]
[myisamchk]
[mysqlhotcopy]
# 将[]替换为空
[root@iZ2ze0gzw63rkie6uwjs74Z lvjing]# sed -n '/\[.*\]/p' my.cnf | sed -e 's/\[//g' -e 's/\]//g'
client
mysqld
mysqldump
mysql
isamchk
myisamchk
mysqlhotcopy

脚本实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#! /bin/bash
#

FILE_NAME=/home/lvjing/my.cnf

function get_all_segments
{
echo "`sed -n '/\[.*\]/p' $FILE_NAME | sed -e 's/\[//g' -e 's/\]//g'`"

}

function count_items_in_segment
{
items=`sed -n '/\['$1'\]/,/\[.*\]/p' $FILE_NAME | grep -v '^#' | grep -v '^$' | grep -v '\[.*\]'`
index=0
for item in $items
do
index=`expr $index + 1`
done

echo $index
}

number=0
for segment in `get_all_segments`
do
number=`expr $number + 1`
items_count=`count_items_in_segment $segment`
echo "$number: $segment $items_count"
done

执行结果:

1
2
3
4
5
6
7
8
[root@iZ2ze0gzw63rkie6uwjs74Z lvjing]# sh example.sh
1: client 9
2: mysqld 206
3: mysqldump 7
4: mysql 1
5: isamchk 12
6: myisamchk 12
7: mysqlhotcopy 1

利用sed删除特定内容

删除命令对照表

查询命令 含义
1d 删除第1行内容
1,10d 删除1行到10行内容
1,+5d 删除1行到6行内容
/pattern1/d 删除每行中匹配到pattern1的行内容
/pattern1/,/pattern2/d 删除匹配到pattern1的行直到匹配到pattern2的所有行内容
/pattern1/,10d 删除匹配到pattern1的行到10行的所有行内容
10,/pattern1/d 删除第10行直到匹配到pattern1的所有行内容

练习

删除/etc/passwd中的第15行 sed -i ‘15d’ passwd
删除/etc/passwd中的第8行到第14行的所有内容 sed -i ‘8,14d’ passwd
删除/etc/passwd中不能登录的用户(筛选条件/sbin/nologin) sed -i ‘/\sbin/nologin/d’ passwd
删除/etc/passwd中以mail开头的行,到以yarn开头的行的所有内容 sed -i ‘/^mail/,/^yarn/d’ passwd
删除/etc/passwd中第一个不能登录的用户,到第13行的所有内容 sed -i ‘/\sbin/nologin/,13d’ passwd
这种方式有缺陷,13行后还会继续匹配不能登录的用户进行删除
删除/etc/passwd中第5行到以ftp开头的所有行的内容 sed -i ‘5,/^ftp/d’ passwd
删除/etc/passwd中已yarn开头到最后行的所有内容 Sed -i ‘/^yarn/,$’ passwd
删除/etc/passwd中不能登录的所有用户 sed -i ‘/\sbin/nologin/d’ passwd

注意:

  • -i 直接修改文件内容
  • /etc/passwd是重要文件,需要拷贝一个文件进行操作
  • $表示最后一行

脚本练习

  1. 删除配置文件中的所有注释行和空行

    1
    sed -i '/^#/d;/^$/d' my.cnf

    注意:上面的命令只会将#顶头的行删除,剩下的行有空格带有#注释的行则不会删除

    1
    2
    my.cnf# 删除带有空格的#行
    sed -i '/[:blank:]*#/' my.cnf

    [:blank:]* 表示空格字符

  1. 在配置文件中所有不以#开头的行前面添加*符号,注意:以#开头的行不添加

    1
    sed -i 's/^[^#]/\*&/g' my.cnf

    ^[^#]非警号开头的行

利用sed修改文件内容

修改命令对照表

编辑命令 含义
1s/old/new/ 替换第1行内容old为new,如果不加数字,则是每一行
1,10s/old/new/ 替换1行到10行的内容old为new
1,+5s/old/new/ 替换1行到6行的内容old为new
/pattern1/s/old/new/ 替换匹配到pattern1的行内容old为new
/pattern1/,/pattern2/s/old/new 替换匹配到pattern1的行直到匹配到pattern2的所有行内容old为new
/pattern1/,10s/old/new/ 替换匹配到pattern1的行到10行的所有行内容old为new
10,/pattern1/s/old/new/ 替换第10行直到匹配到pattern1的所有行内容old为new

练习

修改/etc/passwd中第一行中第1个root为ROOT sed -i ‘1s/root/ROOT/‘ passwd
修改/etc/passwd中第5行到第10行中所有的/sbin/nologin为/bin/bash sed -i ‘5,10s//sbin/nologin//bin/bash/g’ passwd
修改/etc/passwd中匹配到/sbin/nologin,将匹配到行中的login中改为大写的LOGIN sed -i ‘//sbin/nologin/s/login/LOGIN/g’ passwd
修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内容为将这些所有匹配到的行中的bin改为HADOOP sed -i ‘/^root/,/mail/s/bin/HADOOP/g’ passwd
修改/etc/passwd中从匹配以root开头的行,到第15行中的所有行,修改内容为将这些行中的nologin修改为SPARK sed -i ‘/^root/,15s/nologin/SPARK/g’ passwd
修改/etc/passwd中从第15行开始,到匹配到以yarn开头的所有行,修改内容为将这些行中的bin修改为BIN sed -i ‘15,/^yarn/s/bin/BIN/g’ passwd

利用sed追加文件内容

追加用法总结

  • a 在匹配行后面追加
  • i 在匹配行前面追加
  • r 将文件内容追加到匹配行后面
  • w 将匹配行写入指定文件

追加用法示例详解

  • a append

    • passwd文件第10行后面追加”Add Line Behind”

      1
      sed -i '10a Add Line Behind' passwd
  • passwd文件第10行到第20行,每一行后面都追加”Test Line Behind”

    1
    sed -i '10,20s Test Line Behind' passwd
  • passwd文件匹配到/bin/bash的行后面追加”Insert Line For /bin/bash Behind”

    1
    sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
    • i
  • passwd文件匹配到以yarn开头的行,在匹配行前面追加”Add Line Before”

    1
    sed -i '/^yarn/i Add Line Before' passwd
  • passwd文件每一行前面追加”Insert Line Before Every Line”

    1
    sed -i 'i Insert Line Before Every Line' passwd
    • r
  • 将/etc/fstab文件的内容追加到passwd文件的第20行后

    1
    sed -i '20r /etc/fstab' passwd
  • 将/etc/inittab文件的内容追加到passwd文件匹配/bin/bash行的后面

    1
    sed -i '/\/bin\/bash/r /etc/inittab' passwd
  • 将/etc/vconsole.conf文件内容追加到passwd文件特定行后面,匹配已ftp开头的行,到第18行的所有行

    1
    sed -i '/^ftp/,18r /etc/vconsole.conf' passwd
  • w

    • 将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中

      1
      sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
  • 将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.text

    1
    sed -i '10,/^hdfs/w /tmp/sed-1.text' passwd