【Shell脚本编程(五)】文本处理三剑客之sed

1. sed的工作模式

1.1. 基础介绍

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

1.2. 语法格式

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

2. sed的选项

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

3. sed中的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行匹配结束

pattern用法:

  1. LineNumber ------直接指定行号
sed -n "17p" file   #打印file文件的第17行
  1. StartLine,EndLine ------指定起始行号和结束行号
sed -n "10, 20p" file   #打印file文件的10到20行
  1. StartLine,+N ------指定起始行号,然后后面N行
sed -n "10,+5p" file    #打印file文件中从第10行开始,往后面加5行的所有内容
  1. /pattern1/ ------正则表达式匹配的行
sed -n "/^root/p" file      #打印file文件中以root开头的行

sed -n "/^root/p" file      #打印file文件中以root开头的行
  1. /pattern1/,/pattern2/ -------从匹配到pattern1的行,到匹配到pattern2的行
sed -n "/^ftp/,/^mail/p" file   打印file文件中第一个匹配到以ftp开头的行,到第二个匹配到以mail开头的行
  1. LineNumber,/pattern1/ ------从指定行号开始匹配,直到匹配到pattern1的行
sed -n "4,/^hdfs/p" file    打印file文件中从第4行开始匹配,直到以hdfs开头的行
  1. /pattern/,LineNumber ------从pattern1匹配的行开始,直到匹配到指定行
sed -n "/root/,10p" file    #打印file文件中匹配root的行,直到第10行结束

4. sed中的编辑命令详解

4.1. 编辑命令对照表

类别编辑命令含义
查询p打印
增加a行后追加
i行前追加
r外部文件读入,行后追加
w匹配行写入外部文件
删除d删除
修改s/old/new将行内第一个old替换为new
s/old/new/g将行内全部的old替换为new
s/old/new2(g)同一行内只将第二个old替换为new;(2g表示同一行内,只替换从第2个开始到剩下所有的old为new)
s/old/new/ig将行内old全部替换为new,忽略大小写
显示行号=显示行号

反向引用

  • &和\1 引用模式匹配到的整个串
sed "s/1..e/&r/g" file  #在file中搜寻以1开头,然后跟两个任意字符,以e结尾的字符串,在这样的字符串后面追加r
sed "s/\(1..e\)/\1r/g" file #和上面实现一样的功能
  • 上面两种方式实现了一样的功能,分别使用&和\1引用前面匹配到的整个字符串;
  • 两者的区别在于:&只能表示匹配到的完整字符串,只能引用整个字符串;而\1可以使用()对匹配到字符串需要修改的部分;

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

查找test.txt文件中以1开头,紧接着跟两个任意字符,再接一个e的字符串。将找到的字符串中开头的小写l替换成大写的L。

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

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

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

5. 利用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的所有行内容

例子:

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

脚本练习1:

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

编写脚本实现以下功能:输出文件有几个段,并且针对每个段可以统计配置参数总个数

# this is read by the standalone daemon and embedded servers
[client]
port    = 3306
socket  = /tmp/mysql.socket

# This Segment For server
[server]
innodb_buffer_pool_size = 91750M
innodb_buffer_pool_instances = 8
innodb_buffer_pool_load_at_startup = 1
innodb_buffer_pool_dump_at_shutdown = 1
innodb_data_file-path = ibdata1:1G:autoextend
innodb_flush_log_at_trx_commit = 1
innodb_log_buffer_size = 32M
innodb_log_file_size = 2G
innodb_log_files_in_group = 2
innodb_max_undo_log_size = 4G
innodb_undo_directory = undolog
innodb_undo_tablespaces = 95

# this is only for the mysqld standalone daemon
[mysqld]
port = 3306
socket =/tmp/mysqld.sock
basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
sort_buffer_size = 16M
join_buffer_size = 16M
thread_cache_size = 3000
interactive_timeout = 600
wait_timeout = 600

# This Segment For mysqld_safe
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
max_connections = 1000
open_files_limit = 65535
thread_stack = 512K
external-locking = FALSE
max_allowed_packet = 32M

# this is only for embedded server
[embedded]
gtid_mode = on
enforce_gtid_consistency = 1
log_slave_updates
slave-rows-search-algorithms = 'INDEX_SCAN,HASH_SCAN'
binlog_format = row
binlog_checksum = 1
relay_log_recovery = 1
relay-log-purge = 1

# use this geoup for optins that older server don't understand
[mysqld-5.5]
key_buffer_size = 32M
read_buffer_size = 8M
read_rnd_buffer_size = 16M
bulk_insert_buffer_size = 64M
myisam_sort_buffer_size = 128M
myisam_repair_threads = 1
lock_wait_timeout = 3600
explicit_defaults_for_timestamp = 1

预想输出结果:

  1. client 2
  2. server 12
  3. mysqld 12
  4. mysqld_safe 7
  5. embedded 8
  6. mysqld-5.5 9
function get_all_segment
function count_items_in_segment
# 完整脚本文件内容

#!/bin/bash
#
FILE_NAME=/root/lesson/5.6/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

6. 利用sed删除特定内容

6.1. 删除命令对照表

查询命令含义
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的所有行内容

练习例子:

  1. 删除/etc/passwd中的第15行;
sed -i '15d' /etc/passwd
  1. 删除/etc/passwd中的第8行到第14行的所有内容;
sed -i '8,14d' /etc/passwd
  1. 删除/etc/passwd中的不能登录的用户(筛选条件:/sbin/nologin)
sed -i '/\/sbin\/nologin/d' /etc/passwd
  1. 删除/etc/passwd中以mail开头的行,到以yarn开头的行的所有内容;
sed -i '/^mail/,/^yarn/d' /etc/passwd
  1. 删除/etc/passwd中第一个不能登录的用户,到第13行的所有内容;
sed -i '/\sbin/\nologin/,13d' /etc/passwd
  1. 删除/etc/passwd中第5行到以ftp开头的所有行的内容;
sed -i '5,/^ftp/d' /etc/passwd
  1. 删除/etc/passwd中以yarn开头的行到最后行的所有内容;
sed -i '/^yarn/,$' /etc/passwd

典型需求:

  1. 删除配置文件中的所有注释行和空行;
sed -i '/[:blank:]*#/d;/^$/d' nginx.conf
  1. 在配置文件中所有不以#开头的行前面添加*符号,注意:以#开头的行不添加;
sed -i 's/^[^#]/\*&/g' nginx.conf

7. 利用sed修改文件内容

7.1. 修改命令对照表

编辑命令含义
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

练习例子:

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

8. 利用sed追加文件内容

8.1. 追加用法总结

  1. a 在匹配行后面追加
  2. i 在匹配行前面追加
  3. r 在文件内容追加到匹配行后面
  4. w 将匹配行写入指定文件

8.2. 追加用法示例详解

  • a
    • passwd文件第10行后面追加"Add Line Behind";
    sed -i '10a Add Line Behind' passwd
    
    • passwd文件第10行到第20行,每一行后面都追加"Test Line Behind";
    sed -i '10,20a Test Line Behind' passwd
    
    • passwd文件匹配到/bin/bash的行后面追加"Insert Line For /bin/bash Behind"
    sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
    
  • i
    • passwd文件匹配到以yarn开头的行,在匹配行前面追加"Add Line Before"
    sed -i '/^yarn/i Add Line Before' passwd
    
    • passwd文件每一行前面都追加"Insert Line Before Every Line"
    sed -i 'i Insert Line Before Every Line' passwd
    
  • r
    • 将/etc/fstab文件的内容追加到passwd文件的第20行后面
    sed -i '20r /etc/fstab' passwd
    
    • 将/etc/inittab文件内容追加到passwd文件中匹配/bin/bash行的后面
    sed -i '/\/bin\/bash/r /etc/inittab' passwd
    
    • 将/etc/vconsole.conf文件内容追加到passwd文件中特定行后面,匹配以ftp开头的行,到第18行的所有行
    sed -i '/^ftp/,18r /etc/vconsole.conf' passwd
    
  • w
    • 将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
    sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
    
    • 将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt
    sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值