sed用法解析(macos环境BSD shell)

参考:
http://blog.csdn.net/zg_hover/article/details/1804481

sed介绍

1
2
3
4
5
sed可删除(delete)、改变(change)、添加(append)、插入(insert)、合、交换文件中的资料行,或读入其它档的资料到文>件中,也可替换(substuite)它们其中的字串、或转换(tranfer)其中的字母等等。例如将文件中的连续空白行删成一行、"local"字串替换成"remote"、"t"字母转换成"T"、将第10行资料与第11资料合等.
总合上述所言,当sed由标准输入读入一行资料并放入pattern space时,sed依照sed script 的编辑指令逐一对pattern space内的资料执行编辑,之後,再由pattern space内的结果送到标准输出,接着再将下一行资料读入.如此重执行上述动作,直至读>完所有资料行为止.
小结,记住:
(1)sed总是以行对输入进行处理
(2)sed处理的不是原文件而是原文件的拷贝

aa.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
one
#two
#three
#four
five xx
six xx
seven
eight
t hello world t
port
test my car
#port 6379
machine phi
computer phi
Unix

if [ ! -d "/usr/local/fastdfs" ]; then
mkdir /usr/local/fastdfs
fi

abc

删除

1
2
3
4
inputfile="aa.txt"
sed -i '' -e '1d' $inputfile #(删除第一行)
sed -i '' -e '3d' $inputfile #(删除第三行)
sed -i '' -e '1d' -e '2d' -e '3d' $inputfile #(删除第1,2,3行)
1
2
3
4
file="aa.txt"
sed -i '' -e '1,3d' $file #(删除第一到第三行)
sed -i '' -e '4,6d' $file #(删除第4到第6行)
sed -i '' -e '2,$d' $file #$ 最后二行和二行的最后
1
2
3
4
file="aa.txt"
sed -i '' -e '/#/d' $file #(删除含有'#'号的行)
sed -i '' -e '/xx/d' $file #(删除含有字母xx的行)
sed -i '' -e '/xx/!d' $file #(删除 含有xx 以外的行, 反选)
1
2
3
4
file="aa.txt"
sed -i '' -e '/one/,/six/d' $file #(删除从含有单词one到含有单词six的行)
sed -i '' -e '2,/six/d' $file #(删除文件中从第2行到含有six的行)
sed -i '' -e '/two/,7d' $file #(删除从含有two的行到第7行)
1
2
file="aa.txt"
sed -i '' -e '/t.*t/d' $file #(删除含有两个t的行)

替换

Sed 可替换文件中的字串、资料行、甚至资料区。其中,表示替换字串的指令中的函数参数为s;表示替换资料行、或资料区>的指令中的函数参数为c。上述情况以下面三个例子说明。

1
2
3
4
5
6
7
8
9
10
11
file="aa.txt"
sed -i '' -e '1c\'$'\n#!/bin/bash' $file #(把第一行替换成#!/bin/bash)

#等价写法
sed -i '' -e '1c\
#!/bin/bash' $file #(把第一行替换成#!/bin/bash)

# 因此 '$'\n 等价于 手动输入的 回车?

sed -i '' -e '1i\'$'\n#!/bin/bash' $file #(把第一行【插入】#!/bin/bash)
sed -i '' -e '2c\'$'\njust do it' $file #(把第2行替换成just do it)
1
2
3
4
5
6
file="aa.txt"
sed -i '' -e '1,6c\'$'\nI can do it!\
Let\'s start\
hell world' $file

#(换成三行(I can do it! Let's start hello world))
1
2
3
4
file="aa.txt"
sed -e 's/^port/& 6379/' $file
sed -e 's/one/& w2/' $file # one的地方输出 one w2
sed -E -e "s/(test) (my) (car)/[\2 \3 \1]/" $file #结果: [my car test]

flag 参数举例

1
2
3
4
5
6
7
8
9
file="aa.txt"
sed -i '' -E -e 's/^#(port)[ ]+[0-9]+/\1 7001/1' $file #m(10) : 替换行内第m个符合的字串; 记住,是行内的第m个匹配的字串
# BSD shell 正则居然不能用 \d 悲剧.........

sed -ne 's/one/& w2/p' $file #p : 替换第一个和one匹配的字符串为one w2,并输出到标准输出.

sed -e 's/one/& w2/w out.txt' $file #w filename : 该参数会将替换过的内容写入到文件out.txt并输出替换后的整个文件。注意out.txt里写的只是替换过的行。

sed -e 's/one/& w2/' $file #这里的flag 为空, 这样就只是将第一个w1匹配的字符串替换成w1 w2而后面的不进行替换。

位置参数应用举例

1
2
3
4
5
6
7
8
9
file="aa.txt"
# 将文件中含"machine"字串的资料行中的"phi"字串,替换成为"beta"字串
sed -e '/machine/s/phi/beta/g' $file #先找到machine的行, 之后在匹配行中 找phi 替换成beta, 即便用的g flag参数 , 全局也是匹配行

sed -e '1,14 s/port/& extension/g' $file # 把1到14内的port字符串替换成port extension字符串。
sed -e '1,$ s/port/& extension/g' $file # $是最后一行, 因此 1,$ 表示整个文档

sed -E -e '1,/six/ s/(xx)/oo\1/g' $file
sed -E -e '1,/six/ s/xx/& oo/g' $file # 把1到字符串six内的xx字符串替换成xx oo字符串。

####扩展 空行替换成换行

1
sed -e 's/ /\'$'\n/g'

1
2
sed 's/ /\
/g' aa.txt
1
sed -i "" 's/one/before\'$'\nafter/g' $file

参考:
https://stackoverflow.com/questions/1421478/how-do-i-use-a-new-line-replacement-in-a-bsd-sed
https://wenku.baidu.com/view/652dd26804a1b0717ed5dd5d

插入

insert(在匹配行前面插入) i\

1
2
3
4
file="aa.txt"
sed -e '/#/i\'$'\nwords' $file #在#字符的前面插入一行words
sed -e '1i\'$'\nwords' $file #在第一行前加一行words
echo -e "hello\nword"| grep wo | sed -e 's/$/.doc/g' #输出word.doc #按理说是修改啊 , 怎么变成拼接了? $符号真奇妙...

after(在匹配行后面插入) a\

1
2
3
4
#[address] a/ <插入内容> filename
file="aa.txt"
sed -e '/Unix/a\'$'\nLinux' $file #在含有unix的行后添加"Linux"
sed -e '1a\'$'\nhello after' $file #在第一行后添加hello after字符.

扩展

1
2
echo "word"| grep wo | sed -ne 's/'$'/aa/p'
错误 : sed: first RE may not be empty | 从而证明'$'是表示空?

打印

1
2
3
4
5
6
file="aa.txt"
sed -e '/one/ p' $file #打印所有行并重复打印含有then 的行
sed -n '/one/ p' $file #只打印含有then的行
sed -e '1,3 p' $file # 打印所有行并重复1-3行
sed -n '1,3 p' $file # 打印1-3行
sed -n '/if/,/fi/p' $file #打印字符if和fi之间的内容

字元的替换: y

1
2
3
file="aa.txt"
# 匹配范围有点大啊, 得限制指定行
sed -i "" -E -e '/^#port/y/#port 6379/ port 7001/' -e 's/ +port/port/g' $file

反相执行命令 : !

1
sed -E -e '/one|two/!d' $file #删除除了含有one或者two的所有行。

改变文件中的资料: c

1
2
3
4
5
6
7
#基本格式:
#[address1[ ,address2]]c/ filename
#函数参数 c 紧接着 "\" 字元用来表示此行结束 , 使用者所输入的资料必须从下一行输入。如果资料超过一行 , 则须在>每行的结尾加入"\"
sed -e '/six/c\'$'\n666\
777\
888' $file
#表示把含有字符串six的行,该成666\n777\n888。

读入下一行资料: n

1
2
3
4
5
6
#基本格式:
#[address1[ ,address2]] n
sed -i "" -E -ne '/one|two/n' -e 'p' $file # 相当于移除 匹配行
sed -i "" -E -ne '/two|one/n' -e 'p' $file # 表示输出文件,但如果一行含有字符串echo,则输出包含该字符串的下一行。

sed -ne 'n' -e 'p' $file # 输出文中的偶数行

命令的复用

1
2
3
#一次执行多个命令的方式有三种:
sed -i "" -e 's/one/& love/g;s/two/& mail/g' $file #(使用;号把命令隔开,注意前面不加-e参数)
sed -ne '1p' -ne '2p' $file #(使用多个-e参数)

为什么 Mac OS X 的文件打开方式菜单里会有重复图标?

这是Mac传说中的打开方式重复。很多更新后的软件都会出现这种情况。解决方法:打开Terminal,粘贴进以下命令并回车:

1
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user

然后重启Finder即可(control+option点击Finder图标)由于经常要用到这个命令,建议存为script。方法:打开AppleScript Editor,新建,在主窗口粘贴如下文字

do shell script 清除

1
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user

do shell script 重启Finder

1
killall Finder && open /System/Library/CoreServices/Finder.app

然后点 文件-保存,格式选应用程序,确认即可。如此这个命令便存成了直接执行的应用程序,需要用的时候双击一下就会去除重复+重启Finder。

参考:
http://krypted.com/mac-security/lsregister-associating-file-types-in-mac-os-x/
https://www.zhihu.com/question/20599306