linux命令学习(二)——sed

学习资料:《linux大棚命令百篇上》


什么是sed

sed是stream editor的缩写,翻译过来就是“流编辑器”,而实际上它的作用也正如描述的那样。sed命令是一个面向行处理的工具, 以行为处理单位,可以实现很强大的处理能力。sed对每一行进行处理后输出到标准输出,反应在我们可见的角度就是,sed会将修改的内容输出到shell上显示出来,而不会对源文件做任何修改(当然如果想对源文件进行修改也是可以的)。

像学习数学一样,sed的用法可以用一个公式概括:
sed [选项] command file
其中:

  • command:对文件每行(或者选定行)进行的操作。
  • file:要操作的文件。

sed的工作原理

sed在按行处理文件时,会将要处理的那行放入缓冲区中,然后sed命令会对缓冲区中的内容进行处理。处理完成后将缓冲区的内容送入屏幕显示,接着处理下一行,直到文件结束。所以整个处理过程中,sed操作的都是缓冲区的内容,因而并不会对源文件进行任何修改。

下面看一个小例子来展示一下sed的魅力:

首先用一个脚本来创建一个包含行号文件

#! /bin/bash
for i in {1..5}
do
    echo "hello linux $i" >> hello
done

运行脚本后,产生了一个hello文件,文件内容如下:

wangsheng@ubuntu[18:47:21]:~/Documents$ sh file.sh
wangsheng@ubuntu[18:47:26]:~/Documents$ cat hello
hello linux 1
hello linux 2
hello linux 3
hello linux 4
hello linux 5

如果我只想看文件中的第2行,就可以用sed命令这么写:

wangsheng@ubuntu[18:49:47]:~/Documents$ sed -n '2p' hello
hello linux 2

可以看到只显示了hello文件中的第2行。这个例子很简单,只是展示一下sed的基本用法,后面会对sed的用法进行详细描述。这里的-n是sed提供的一个选项,而'2p'就是sed的command部分表示打印第二行;hello是file部分,表示操作的是hello这个文件。


sed的详细用法

花样的命令

命令是sed用法中command部分,sed之所以拥有强大的功能,就是因为其command部分可以组合成非常多的花样。常用的command通常由两部分构成,一部分是范围设定,也就是选定行;另一部分是动作处理,即对选定的行执行什么样的操作。

范围设定

范围设定,顾名思义就是sed命令需要对哪一行或者哪几行进行操作。值得注意的是,如果不选定行,那么默认对所有行执行此操作。常用的范围设定有如下几种形式:

  • x:x为行号,表示选定第x行
    #显示第2行
    wangsheng@ubuntu[18:49:47]:~/Documents$ sed -n '2p' hello
    hello linux 2
    
  • x,y:从第x行到第y行
    #显示2-4行
    wangsheng@ubuntu[19:40:50]:~/Documents$ sed -n '2,4p' hello
    hello linux 2
    hello linux 3
    hello linux 4
    
  • x,$:从第x行到最后一行
    #显示第4行到最后一行
    wangsheng@ubuntu[19:44:41]:~/Documents$ sed -n '4,$p' hello
    hello linux 4
    hello linux 5
    
  • x,y!:不包含指定行号x到y的行
    #显示除了第3行的所有行
    wangsheng@ubuntu[19:47:33]:~/Documents$ sed -n '3!p' hello
    hello linux 1
    hello linux 2
    hello linux 4
    hello linux 5
    
  • /pattern/:查询包含该模式的行,这里的pattern可以使用正则表达式。
    #查询显示含有5的行
    wangsheng@ubuntu[19:47:40]:~/Documents$ sed -n '/5/p' hello
    hello linux 5
    #查询显示含有linux的行
    wangsheng@ubuntu[19:50:47]:~/Documents$ sed -n '/linux/p' hello
    hello linux 1
    hello linux 2
    hello linux 3
    hello linux 4
    hello linux 5
    
  • x,/pattern/ :通过行号和模式查询匹配行,表示从第x行到匹配该模式的行。

动作处理

动作处理会提供很多丰富的动作供我们选择,可以利用这些动作对某行内容进行加入、删除、修改等操作。这里介绍几个常用的动作:

  • p : 打印,将选中的那行打印输出到屏幕上。通常 p 会与参数 sed -n 一起用。(关于-n选项的作用,后面在介绍sed选项的时候会详细说明)。

    #源文件
    wangsheng@ubuntu[20:04:00]:~/Documents$ cat hello
    hello linux 1
    hello java 2
    hello c++ 3
    hello android 4
    hello php 5
    #显示第2行
    wangsheng@ubuntu[20:04:06]:~/Documents$ sed -n '2p' hello
    hello java 2
    #显示最后一行
    wangsheng@ubuntu[20:05:38]:~/Documents$ sed -n '$p' hello
    hello php 5
    #显示含有java的行
    wangsheng@ubuntu[20:16:25]:~/Documents$ sed -n '/java/p' hello
    hello java 2
    
  • a : 增加,a 的后面可以接字符串,而这些字符串会在新的一行出现(目前的下一行),而如果想添加多行,可以使用\n换行符。

    #在文件末添加一行hello python
    wangsheng@ubuntu[20:08:48]:~/Documents$ sed '$a hello python' hello
    hello linux 1
    hello java 2
    hello c++ 3
    hello android 4
    hello php 5
    hello python
    #使用\n可以添加换行,例如本例在含有android行的下一行添加了两行内容
    wangsheng@ubuntu[20:17:39]:~/Documents$ sed '/android/a hello\nworld' hello
    hello linux 1
    hello java 2
    hello c++ 3
    hello android 4
    hello
    world
    hello php 5
    
  • c : 行替换,c 的后面可以接字符串,这些字符串可以替换 n1,n2 之间的行。

    #第2行替换为hello world
    wangsheng@ubuntu[20:09:00]:~/Documents$ sed '2c hello world' hello
    hello linux 1
    hello world
    hello c++ 3
    hello android 4
    hello php 5
    #第3行至最后一行替换为hello world
    wangsheng@ubuntu[20:11:06]:~/Documents$ sed '3,$c hello world' hello
    hello linux 1
    hello java 2
    hello world
    
  • d : 删除行,因为是删除,所以 d 后面通常不接任何内容,表示删除选定行的内容。

    #删除第1行
    wangsheng@ubuntu[20:12:58]:~/Documents$ sed '1d' hello
    hello java 2
    hello c++ 3
    hello android 4
    hello php 5
    #删除含有java的行
    wangsheng@ubuntu[20:19:05]:~/Documents$ sed '/java/d' hello
    hello linux 1
    hello c++ 3
    hello android 4
    hello php 5
    
  • s : 替换,可以直接进行搜寻替换的工作。通常 s 可以搭配正则表达式。

    格式:sed 's/要替换的字符串/新的字符串/g' (要替换的字符串可以用正则表达式)

    #搜索含有java的行,并将该行的java替换成javaee
    wangsheng@ubuntu[20:19:49]:~/Documents$ sed '/java/s/java/javaee/g' hello
    hello linux 1
    hello javaee 2
    hello c++ 3
    hello android 4
    hello php 5
    #也可以使用该功能删除某个字符串,例如本例将java替换成空即删掉了第2行的java
    wangsheng@ubuntu[20:25:13]:~/Documents$ sed '/java/s/java//g' hello
    hello linux 1
    hello  2
    hello c++ 3
    hello android 4
    hello php 5
    

    有时候我们不想在当前行的下一行或者上一行添加内容,而希望在行首或行尾追加内容时怎么办呢?

    其实就可以使用s功能。其中^表示行首,$表示行尾

    #在每行行首添加head------
    wangsheng@ubuntu[20:29:56]:~/Documents$ sed 's/^/head------/g' hello
    head------hello linux 1
    head------hello java 2
    head------hello c++ 3
    head------hello android 4
    head------hello php 5
    #在每行行尾追加------tail
    wangsheng@ubuntu[20:35:12]:~/Documents$ sed 's/$/------tail/g' hello
    hello linux 1------tail
    hello java 2------tail
    hello c++ 3------tail
    hello android 4------tail
    hello php 5------tail
    #在第1行行尾追加------tail
    wangsheng@ubuntu[20:35:36]:~/Documents$ sed '1s/$/------tail/g' hello
    hello linux 1------tail
    hello java 2
    hello c++ 3
    hello android 4
    hello php 5
    

    另外,如果说s是代表替换,那么末尾的g是什么意思呢?

    其实字符g代表的意思是每行出现的字符全部替换,如果想在特定字符处添加,g就有用了,否则只会替换每行第一个,而不继续往后找了。

  • r : 文件插入,可以在当前行的下一行插入指定文件中的内容。

    #需要插入的文件内容
    wangsheng@ubuntu[20:28:34]:~/Documents$ cat foo
    +++this is file in foo+++
    #使用a动作插入时,只会将foo当做字符串插入
    wangsheng@ubuntu[20:27:46]:~/Documents$ sed '/java/a foo' hello
    hello linux 1
    hello java 2
    foo
    hello c++ 3
    hello android 4
    hello php 5
    #使用r命令插入时,会将foo代表的文件内容插入
    wangsheng@ubuntu[20:28:12]:~/Documents$ sed '/java/r foo' hello
    hello linux 1
    hello java 2
    +++this is file in foo+++
    hello c++ 3
    hello android 4
    hello php 5
    

好用的选项

刚才我们已经提到了sed的命令的基本构成,下面来看看sed有哪些好玩的选项。

  • -n:使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的内容一般都会被输出到屏幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被输出出来。

    #使用-n选项,只会输出处理的那一行
    wangsheng@ubuntu[20:43:59]:~/Documents$ sed -n '/java/a ======' hello
    ======
    #不使用-n选项,输出所有行
    wangsheng@ubuntu[20:44:22]:~/Documents$ sed '/java/a ======' hello
    hello linux 1
    hello java 2
    ======
    hello c++ 3
    hello android 4
    hello php 5
    
  • -e:如果我要执行的动作包含两个或以上怎么办呢?这也很简单,sed的-e属性就是支持这个功能的,只要在每个动作之前分别加上-e选项即可。

    #前一个command输出1-2行,后一个command输出第4行
    #每个command之前均加上-e选项就可以同时处理两个动作了
    wangsheng@ubuntu[20:44:33]:~/Documents$ sed -n -e '1,2p' -e '4p' hello
    hello linux 1
    hello java 2
    hello android 4
    
  • -f:如果设定的command部分太长,那么可以将command部分内容写到一个单独的文件中,然后使用-f选项来指定这个文件作为我们sed命令的command部分。

    #已经写好的command,存储在文件中
    wangsheng@ubuntu[20:49:12]:~/Documents$ cat command
    /java/,/android/p
    #使用-f选项指定command文件
    wangsheng@ubuntu[20:49:16]:~/Documents$ sed -n -f command hello
    hello java 2
    hello c++ 3
    hello android 4
    
  • -i:直接修改读取的文件内容,而不是输出到屏幕上。要注意此选项会直接改变源文件的内容,如果用此命令对系统配置文件修改的话,那么如果出现什么无法挽回的后果也只能怪自己作死了。

    #源文件
    wangsheng@ubuntu[20:49:32]:~/Documents$ cat hello
    hello linux 1
    hello java 2
    hello c++ 3
    hello android 4
    hello php 5
    #第2行后添加新行,内容为this is a new line
    wangsheng@ubuntu[20:52:32]:~/Documents$ sed -i '2a this is a new line' hello
    #源文件被修改
    wangsheng@ubuntu[20:53:20]:~/Documents$ cat hello
    hello linux 1
    hello java 2
    this is a new line
    hello c++ 3
    hello android 4
    hello php 5
    

sed实践——自动评分的脚本

学了知识当然是为了用的,那么我们就用一个实际的例子来看看sed的应用。

老师在服务器上为我们每个人创建了一个student_ids文件,里面有所有同学的名单,每个同学都要在该文件中为其他同学打分。为了完成评分的工作,需要使用vi打开再一个个编辑,而且还不能全打满分或者有规律地打分,于是本着能偷懒就偷懒的原则,能不能写一个自动打分脚本呢?显然,使用sed这么强大的行处理功能实现起来肯定是没问题的。

最终写出来的脚本如下:

#!/bin/bash
count=0
#统计行数
while read line
do
    count=$(($count+1))
done < student_ids

for (( i=1; i<="$count"; i++ ))
do
    #产生84-99之间的随机数
    let score=$RANDOM%15+84
    #第i行行尾追加随机数
    sed -i "${i}s/$/ $score/g" student_ids
done

首先得到该文件的行数,并用一个变量count记录下来。然后循环count次,每次循环产生一个84-99之间的随机数,使用sed命令将此随机数插入到该行的行尾,然后下一次循环再对下一行执行同样的操作。值得注意的是,这里sed使用了-i选项,表示直接对源文件执行此操作,另外使用了强引用“”,而不是弱引用‘’。如果是弱引用的话,那么会将$score部分当做是一个字符串,直接在每行行尾加上了$score这样的字符串;而如果使用强引用的话,则直接将$score代表的随机数插入到行尾。

最后效果如下:

#student_ids源文件
wangsheng@ubuntu[21:03:12]:~/Documents$ cat student_ids
142006010124
142006010125
142006010126
142006010127
142006010128
142006010130
142006010121
142006010122
#执行脚本
wangsheng@ubuntu[21:03:27]:~/Documents$ sh autograding.sh
8 lines completed!
#student_ids文件已经被修改
wangsheng@ubuntu[21:03:32]:~/Documents$ cat student_ids
142006010124 98
142006010125 90
142006010126 94
142006010127 89
142006010128 96
142006010130 84
142006010121 94
142006010122 98
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 学习资料:《linux大棚命令百篇上》 awk介绍及简单实用 以下是在网上找到的两个awk的介绍: awk是一种处...
    陌上疏影凉阅读 681评论 0 3
  • 本文笔记源自这里——[实验楼]欢迎大家在下面交流其中有问题的地方喜欢请点收藏,每日更新(全部已亲自实践). 一. ...
    东皇Amrzs阅读 3,842评论 7 54
  • 玩家进行游戏,仅仅是因为想完成一款游戏么?还是希望通过游戏达到什么目的?接下来,我们简单讨论一下这个问题。 游戏作...
    清寒如秋阅读 1,049评论 0 0
  • 苦恋三部曲(组诗) ✿ 夕阳瘦 一. 求婚 新月般纤柔 流水无波的轻盈 你带来风的律动 指尖上絮语 你把四季雕刻成...
    水畔细语阅读 608评论 2 2