vimer linux kernel 爱好者

sed的简单实用

2018-09-21

要说 shell 编程,绝对是一个瑞士军刀级别的工具,效率惊人的很。

sed 在特定行插入文本

这个需求是我自己整理博客时提出来的。为什么?原因是这样的,在我上一篇文章 中,我也已经提出来了,更换了博客主题,同时也无意间看到该博主实现了标题导航 的功能,这个确实吸引人的,那么,我的博客应该如何实现这个功能呢?

幸运的是,我的文档就是使用Markdown,只需添加两行代码即可完成:

* content
{:toc}

但是,这个代码要添加在什么位置呢?一般来说,我的博客正文是这样的:

---
title: awk和sed的简单实用
category: shell
layout: post
---

一般情况下也就是从第六行开始,为了安全起见,第六行空一行。下面是我根据网络 资源搜集的脚本并测试还可以的:

sed -i '7 i* content\n{:toc}\n' `grep layout -rl .`

这句命令简单了解一下就是,sed命令,指定在第7行插入* content\n{:toc}\n,’\n’ 是换行的意思,i是在第7行前,a是在第7行后,这里是为了与vim相一致。后面一句grep是 为了能够在多个文件中插入(另一句就是如何在特定目录中的所有文件中特定的位置插入代码)

来自coolshell

替换

一般的模式是's/regexp/replacement/flags'sed 的模式匹配就是使用/开始,以上面的连接中例子:

$ cat pets.txt
This is my cat
my cat's name is betty
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam

则命令:

sed "s/my/Bo's/g" pets.txt

其中, s是替换, g是全局

如果想将输出的结构保存在一个文本内

  1. 可以使用重定向的方式
  2. 使用-i选项

在这里也可以看出来,sed 后面的操作(不算-*这种选项),首先是动作s,接着是model-str1/model-str2,最后是作用域符号。 上面的说法有些不准确,更准确的说法是s后面紧跟的东西是正则表达式。

s可以指定范围,3,6s/reg/matched/g,g也可以同理。

sed 's/^/#/g' pets.txt

在每一行的第一列插入字符#

一些简单的正则表达式介绍:

  1. ^,一行的开头 ^# 配置每行以 # 开头
  2. $ 每行结尾 }$ 匹配以}结尾
  3. \< 表示词首 \<abc 匹配以abc为首的
  4. . 任何单个字符
  5. 星号 匹配0次或者多次
  6. []集合,其中^为取反

&在匹配域中可以作为匹配的变量来使用。

yubo@win:~/test/shell$ sed 's/my/[&]/g' word.txt
this is [my] cat
[my] cat's name is betty
This is [my] dog
[my] dog's name is frank
This is [my] fish
[my] fish's name is george
This is [my] goat
[my] goat's name is adam

匹配括号

匹配方括号

方括号匹配,需要转义.

echo "[]" | sed 's/\[.*\]/aaa/g'  # aaa

匹配圆括号

这个不需要转义。

echo "()" | sed 's/()/[]/g' # []

匹配花括号

不需要转义。

echo "{}" | sed 's/{}/()/g' # ()

当需要匹配数字、字母等使用中括号时(比如说为了匹配的个数),不要转义,但是,大括号作为特殊字符的时候,需要转义

echo "333" | sed 's/[0-9]\{3\}/[&]/g' # [333]

当需要适配符,比如\1来代替匹配变量时,是需要对大括号加转义的。

echo "{123456}" | sed 's/{\([0-9]*\)}/\1/g'
# 123456

与此对应的还有 +* 在做为特别字符时候+必须转义为 \+

才有效, 而*则不需要。

echo "ccc" | sed 's/c*/i like &/g' #  正确 i like ccc
echo "ccc" | sed 's/c\*/i like &/g'  # 错误 ccc
echo "ccc" | sed 's/c\+/i like & too/g' # 正确 i like ccc too

这也就是下面介绍的. 正则表达式中”方括号”特殊的符号 sed正则表达式匹配,各种括号的转义和不转义

圆括号匹配

一个重要的原则是,使用括号括起来的正则表达式,是可以当成变量来使用的,其中, 使用的话使用\1,\2....

cat my.txt
This is [my] cat, [my] cat's name is betty
This is [my] dog, [my] dog's name is frank
This is [my] fish, [my] fish's name is george
This is [my] goat, [my] goat's name is adam

插入

根据特定字段插入

比如,我想在 http 前面插入 [trusted=yes]这个字段使用

sed -i 's/指定字段/目标字段&/' file

cat /etc/apt/sources.list
deb  http://ftp.ports.debian.org/debian-ports/ sid main
deb-src  http://ftp.ports.debian.org/debian-ports/ sid main
# sed -i 's/http/[trusted=yes] &/' tmp.txt
# cat tmp.txt
deb [trusted=yes] http://ftp.ports.debian.org/debian-ports/ sid main
deb-src [trusted=yes] http://ftp.ports.debian.org/debian-ports/ sid main

参考

sed 的命令

sed的命令模式在形式上与上述不同,可以通过表达式最前面的字符判断是不是命令, (一般都是 sed “/reg/express/”)

N

-n把下一行的内容纳入当成缓冲区做匹配.

p命令

可以看成一个grep的命令 以上面my.txt为例,使用

sed '/fish/p' my.txt
This is [my] cat, [my] cat's name is betty
This is [my] dog, [my] dog's name is frank
This is [my] fish, [my] fish's name is george
This is [my] fish, [my] fish's name is george
This is [my] goat, [my] goat's name is adam''''

我们看到匹配的fish打印了两行,这是因为sed也处理的信息也打印出来了.解决这个问题的方 式是使用-n选项。

sed -n '/fish/p' my.txt
This is [my] fish, [my] fish's name is george

FAQ

这里所谓的FAQ,是自己将不会的记录在这里,定期回顾.

罕见的用法

这个命令来自于aosp,来看一看具体的表现形式:

 sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p"

当时,看这个命令没少费劲,一个是表现形式,一个是[[:blank:]].

  1. 空格问题 首先来看[[:blank:]],这个是寻找以非NULL结尾的空白格语句(常见于DOS系统中可能) here解释的很清楚,
sed '/^$/d' filename

只会针对NULL的列,另一个方案使用非POSIX的\s*,其中\s是非字符串的意思, 星号是0个或者多个,但是这个是NON POSIX的方式.

sed '/^\s*$/d' file

你可以看一下将会打印所有的none black lines

grep -v '^/s*$' file

POSIX的方案是:

sed '/^[[:blank:]]*$/d' file
  1. 处理字符串 这一条到现在我都没找到正式的官方介绍,很是苦闷。
    sed -En '/^password: / s,^password: "(.*)"$,\1,p'
    

    先不看-En,在上述的代码中,比较陌生的是,这只是一个定界符,我们可以使用任何符号去 当做定界符,为了上面好分析,我们可以使用#或者/这里使用,是因为要处理的是 passwd文件,里面有大量的/符号.

    sed '/^password: / s#^password: "(.*)"$#\1#p'
    

    其中:

/^password: /: finds an input line that starts with password: ;

s#^password: "(.*)"$#\1#p : finds and captures double-quoted string after password: and replaces the entire line with the captured string \1 ( so all that remains is the password )””

他这里首先查找了在使用?


上一篇 blog更换主题

下一篇 shell的cut用法

Comments

Content