要说 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
是
为了能够在多个文件中插入(另一句就是如何在特定目录中的所有文件中特定的位置插入代码)
替换
一般的模式是'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
是全局
如果想将输出的结构保存在一个文本内
- 可以使用重定向的方式
- 使用
-i
选项
在这里也可以看出来,sed 后面的操作(不算-*这种选项),首先是动作s
,接着是model-str1/model-str2
,最后是作用域符号。
上面的说法有些不准确,更准确的说法是s
后面紧跟的东西是正则表达式。
s
可以指定范围,3,6s/reg/matched/g
,g
也可以同理。
sed 's/^/#/g' pets.txt
在每一行的第一列插入字符#
一些简单的正则表达式介绍:
^
,一行的开头^#
配置每行以 # 开头$
每行结尾}$
匹配以}
结尾\<
表示词首\<abc
匹配以abc
为首的.
任何单个字符星号
匹配0次或者多次[]
集合,其中^
为取反
&
在匹配域中可以作为匹配的变量来使用。
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:]]
.
- 空格问题
首先来看
[[: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
- 处理字符串
这一条到现在我都没找到正式的官方介绍,很是苦闷。
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 )””
他这里首先查找了在使用?