【记录】sed 学习

原文链接
http://zouzhipeng.com/2017/05/25/%E3%80%90%E8%AE%B0%E5%BD%95%E3%80%91sed%20%E5%AD%A6%E4%B9%A0/

本文是慕课网 《实例妙解sed 和 awk 的秘密》》 的学习记录的第二部分:sed。

Linux 三大利器: grep, sed, awk.

1. sed 工作原理

sed 是一种流处理编辑器

  1. 文本或管道输入(正则选定文本)
  2. 读入一行到模式空间(临时缓冲区)
  3. sed命令处理
  4. 结果输出到屏幕
  5. 重复第2步操作

sed 一次处理一行内容

sed 不改变文件内容 (除非重定向)

2. 使用 sed 格式

  • 命令行格式
$ sed [options] 'command' file(s)

options: -e, -n

command: 行定位(正则) + sed命令 (操作)

  • 脚本格式
$ sed -f scriptfile file(s)

举个栗子:

// p 即 print,打印命令
$ sed -n 'root/p'

2. sed 基本操作命令

1. -p 打印相关命令

$ sed 'p' passwd

结果每一行都被输出了两次,为什么?

sed 原理为读入一行,输出一行到屏幕,现在中间又加入一个打印的步骤,所以就出现了重复。

如何规避?

再添加一个 -n 参数即可。该参数一般与 p 参数一起使用,表示只打印出相关的行。

$ sed -n 'p' passwd

2. 行定位

  • 定位一行: x; /pattern/;
// 打印第33行
$ sed -n '33p' passwd
_svn:*:73:73:SVN Server:/var/empty:/usr/bin/false

通过 nl 命令查看行号

// 打印第33行
$ nl passwd | sed -n '33p'
    33  _svn:*:73:73:SVN Server:/var/empty:/usr/bin/false
// 打印包含root的行
$ sed -n '/root/p' passwd
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_cvmsroot:*:212:212:CVMS Root:/var/empty:/usr/bin/false
  • 定位多行(范围): x,y; /pattery/,x;
// 打印10到20行
$ nl passwd | sed -n '10,20p'
// 打印第一个包含root的行到第一个包含www的行之间所有的行
$ nl passwd | sed -n '/root/,/www/p

都是匹配第一个

  • 取反操作 !
// 不打印第20行
$ nl passwd | sed -n '20!p'
// 不打印10到20行
$ nl passwd | sed -n '10,20!p'
  • 定位间隔几行 first~step
// 输出奇数行,Mac亲测无效,CentOS 有效
$ nl passwd | sed -n '1~2p'
     1  root:x:0:0:root:/root:/bin/bash
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     ...

3. sed 行处理命令

1. 基本操作命令(Mac下失效)

a:新增行

i:插入行

c:替代行

d:删除行

// 在第5行后面添加分隔线
$ nl passwd | sed '5a ==============='
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
===============
     6  sync:x:5:0:sync:/sbin:/bin/sync
     ...
// 在第1-5行后面添加分隔线
$ nl passwd | sed '1,5a ==============='
     1  root:x:0:0:root:/root:/bin/bash
===============
     2  bin:x:1:1:bin:/bin:/sbin/nologin
===============
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
===============
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
===============
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
===============
     6  sync:x:5:0:sync:/sbin:/bin/sync
     ...
// 在第1-5行之前添加分隔线
$ nl passwd | sed '5i ==============='
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
===============
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
// 第5行替换为其他内容
$ nl passwd | sed '5c ==============='
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
===============
     6  sync:x:5:0:sync:/sbin:/bin/sync
$ nl passwd | sed '1,5c ==============='
===============
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

注意替换规则与插入规则的区别,连续行的替换是整体替换,而不是一行一行。

随意感受一下

$ nl passwd | sed '/nologin/c ==============='
     1  root:x:0:0:root:/root:/bin/bash
===============
===============
===============
===============
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     8  halt:x:7:0:halt:/sbin:/sbin/halt
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
===============
    25  zzp:x:1000:1000::/home/zzp:/bin/bash
===============
// 删除行,不会影响源文件
$ nl passwd | sed '/root/d'
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     6  sync:x:5:0:sync:/sbin:/bin/sync

2. 案例1 修改配置文件

简单的操作就可以替代 vim 了

// 在文档末尾增加一些内容
$ sed '$a new line \nnew line'

3. 案例2 删除文本中的空行

$ sed '/^$/d' file

4. 案例3 log 中提取 error

$ sed -n '/Error/p' file

4. sed 替换命令 s (核心,重点)

$ sed 's/nologin/login/' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/login
daemon:x:2:2:daemon:/sbin:/sbin/login
adm:x:3:4:adm:/var/adm:/sbin/login
lp:x:4:7:lp:/var/spool/lpd:/sbin/login
$ sed 's/:/%/' passwd
root%x:0:0:root:/root:/bin/bash
bin%x:1:1:bin:/bin:/sbin/nologin
daemon%x:2:2:daemon:/sbin:/sbin/nologin
adm%x:3:4:adm:/var/adm:/sbin/nologin
lp%x:4:7:lp:/var/spool/lpd:/sbin/nologin

这里出现了一个问题,每一行只替换了第一个匹配。

添加全局标记 g 即可

$ sed 's/:/%/g' passwd
root%x%0%0%root%/root%/bin/bash
bin%x%1%1%bin%/bin%/sbin/nologin
daemon%x%2%2%daemon%/sbin%/sbin/nologin
adm%x%3%4%adm%/var/adm%/sbin/nologin
lp%x%4%7%lp%/var/spool/lpd%/sbin/nologin

1. 案例:获取网卡中的ip

思路:首先取出 ifconfig 命令输出的第二行,然后将 ip 前后两部分无用的信息分别替换为空即可。

// 取出所需行
$ ifconfig | sed -n '/inet .*broadcast.*/p'
        inet 172.17.147.89  netmask 255.255.240.0  broadcast 172.17.159.255
// 替换ip前的字符为空
$ ifconfig | sed -n '/inet .*broadcast.*/p' | sed 's/inet //'
        172.17.147.89  netmask 255.255.240.0  broadcast 172.17.159.255
// 替换ip后的字符为空
$ ifconfig | sed -n '/inet .*broadcast.*/p' | sed 's/inet //' | sed 's/netmask.*//'
        172.17.147.89
// 替换可能漏掉的空格
$ ifconfig | sed -n '/inet .*broadcast.*/p' | sed 's/inet //' | sed 's/netmask.*//' | sed 's/\ //'
       172.17.147.89

3. sed 高级操作命令

1. -{ }: 多个sed命令,用;分开

// 先将2-10行删除,然后将false替换为true,两个命令写到一起,这里{}不用转义
$ nl passwd | sed '{2,10d;s/false/true/}'
     1  root:x:0:0:root:/root:/bin/bash
    11  games:x:12:100:games:/usr/games:/sbin/nologin
    12  ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    13  nobody:x:99:99:Nobody:/:/sbin/nologin

2. -n 读取下一个输入行(用下一个命令处理)

有一个跳行的过程

$ nl passwd | sed -n '{n;p}'
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     6  sync:x:5:0:sync:/sbin:/bin/sync
     8  halt:x:7:0:halt:/sbin:/sbin/halt

这就实现了偶数行输出。如何输出奇数行?先输入p后跳行即可。

$ nl passwd | sed -n '{p;n}'
     1  root:x:0:0:root:/root:/bin/bash
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

之前的等效做法

$ nl passwd | sed -n '1~2p'
$ nl passwd | sed -n '2~2p'

2,5,8... 这样输出呢?

// 两种方法等效,推荐使用前者
$ nl passwd | sed -n '2~3p'
$ nl passwd | sed -n '{n;p;n}'

3. & 符号使用

-&: 替换固定字符串
优化替换操作。

案例: passwd 文件中的用户名后面添加空格,便于阅读。

分析:

  • 用户名都是在行首,可以包含字母,中划线和下划线。

使用 &,就没有必要在替换后的字符串中将替换前的正则重新再写一遍。

$ sed 's/^[a-z_-]\+/&   /' passwd
root   :x:0:0:root:/root:/bin/bash
bin   :x:1:1:bin:/bin:/sbin/nologin
daemon   :x:2:2:daemon:/sbin:/sbin/nologin

原来的写法可能是这样的,还不一定能实现。

$ sed 's/^[a-z_-]\+/^[a-z_-]\+  /' passwd

案例: 大小写转换

将用户名的首字母转化为大写/小写

元字符

  • \u \l (首字母转换)
  • \U \L (字符串转换)
  • uppercase, lowercase
$ sed 's/^[a-z_-]\+/\u&/' passwd
Root:x:0:0:root:/root:/bin/bash
Bin:x:1:1:bin:/bin:/sbin/nologin
Daemon:x:2:2:daemon:/sbin:/sbin/nologin
Adm:x:3:4:adm:/var/adm:/sbin/nologin
$ sed 's/^[a-z_-]\+/\U&/' passwd
ROOT:x:0:0:root:/root:/bin/bash
BIN:x:1:1:bin:/bin:/sbin/nologin
DAEMON:x:2:2:daemon:/sbin:/sbin/nologin

文件名转大写

$ ls *.txt | sed 's/^\w\+/\U&/'

4. ()符号

一个括号代表一个要被替换的部分。注意转义括号。

示例:数据筛选,获取passwd中 USER, UID 和 GID

一个一个获取

$ sed 's/\(^[a-z_-]\+\):.*$/\1/' passwd
root
bin
daemon
adm
$ sed 's/\(^[a-z_-]\+\):x:\([0-9]\+\).*$/\1 \2/' passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
$ $ sed 's/\(^[a-z_-]\+\):x:\([0-9]\+\):\([0-9]\+\).*$/USER:\1 UID:\2 GID:\3/' passwd
USER:root UID:0 GID:0
USER:bin UID:1 GID:1
USER:daemon UID:2 GID:2
USER:adm UID:3 GID:4
USER:lp UID:4 GID:7
USER:sync UID:5 GID:0
USER:shutdown UID:6 GID:0
USER:halt UID:7 GID:0
USER:mail UID:8 GID:12
USER:operator UID:11 GID:0
USER:games UID:12 GID:100
USER:ftp UID:14 GID:50
USER:nobody UID:99 GID:99

示例: 获取网卡IP

分析:之前我们是将IP行分为三段,分别将前后两段无用的信息替换为空。现在我们还是将该行分为三段,但是只要获取第二段即可。

先找到IP所在的行,匹配第一部分,注意别漏了空格。第二部分用括号括起来,用于输出,第三部分不用管。最后将第二部分打印输出即可。

$ ifconfig | sed -n '/inet /p' | sed -n '1p' | sed 's/[a-z ]\+\([0-9.]\+\) .*$/\1/'
172.17.147.89

5. rw 命令

读和写命令,文件互操作

r: 复制指定文件插入到匹配行

w: 复制匹配行拷贝至指定文件

$ echo -e '11111\n22222\n33333' > 123.txt
$ echo -e 'aaaa\nbbbbb\ncccc' > abc.txt
// 读取文件123.txt,将结果放入到abc.txt 中,放置位置为第一行后。
$ sed '1r 123.txt' abc.txt
aaaa
11111
22222
33333
bbbbb
cccc

如果不指定行号,将会在目录文件的每一行后面插入读取到的文件内容。

读文件后,两个文件的内容都没有发生改变。

// 将123.txt文件的第一行写入abc.txt
$ sed '1w abc.txt' 123.txt

写操作后,abc.txt内容受影响,原内容消失,只剩下本次操作写入的内容。不指定行号就相当于文件内容拷贝。

引号中是rw直接操作的文件。使用w的时候要格外小心。

6. q 命令

退出 sed

在执行中间提前退出sed,没必要每次都执行到最后一行。

// 执行到第5行退出sed
$ nl passwd | sed '5q'
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
// 找到第一个 nologin 就退出 sed
$ nl passwd | sed '/nologin/q'
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 11,986评论 2 34
  • 本文承接之前写的三十分钟学会AWK一文,在学习完AWK之后,趁热打铁又学习了一下SED,不得不说这两个工具真的堪称...
    mylxsw阅读 4,356评论 3 74
  • 基础命令 主要的命令和快捷键 Linux系统命令由三部分组成:cmd + [options]+[operation...
    485b1aca799e阅读 994评论 0 0
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 98,293评论 9 468
  • 说明:本篇文章来自老男孩,这里只做备份记录 功能说明 Sed是Stream Editor(流编辑器)缩写,是操作、...
    think_lonely阅读 681评论 0 2