- 浏览: 12831 次
- 来自: 深圳
文章分类
最新评论
Shell脚本之sed篇
目录:
一、概述
二、sed基本语法格式
三、简单正则表达式
四、sed脚本指令(注释、替换、删除、追加、打印、下一行、读写文件、退出、多行模式)
五、综合案例
一、概述
1.sed是一款流编辑工具,用来对文本进行过滤与替换工作,特别是当你想要对几十个配置文件做统计修改时,你会感受到sed的魅力!
sed通过输入读取文件内容,但一次仅读取一行内容进行某些指令处理后输出,所以sed更适合于处理大数据文件。
2.sed流程:
* 通过文件或管道读取文件内容。
* sed并不直接修改源文件,而是将读入的内容复制到缓冲区中,我们称之为模式空间(pattern space)。
* 根据sed的指令对模式空间中的内容进行处理并输出结果,默认输出至标准输出即屏幕上。
输入
------------------------------------------------
|
|
v
v
读取一行内容,并复制到模式空间 <------------ sed 指令
|
|
v
v
------------------------------------------------
输出经过处理后的内容
*****************************************************************************************************
二、sed基本语法结构
sed Options... [script] [inputfile...]
sed 选项... [脚本指令] [输入文件]
如果没有输入文件,则sed默认对标准输入进行处理(即键盘输入)。脚本指令是第一个不以“-”开始的参数。
1.选项含义:
--version 显示sed版本。
--help 显示帮助文档。
-n,--quiet,--silent 静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印
模式空间中的内容,这些选项可以屏蔽自动打印。
-e script 允许多个脚本指令被执行。
-f script-file,
--file=script-file 从文件中读取脚本指令,对编写自动脚本程序来说很棒!
-i,--in-place 直接修改源文件,经过脚本指令处理后的内容将被输出至源文件(源文件被修改)
慎用!
-l N, --line-length=N 该选项指定l指令可以输出的行长度,l指令用于输出非打印字符。
--posix 禁用GNU sed扩展功能。
-r, --regexp-extended
在脚本指令中使用扩展正则表达式
-s, --separate 默认情况下,sed将把命令行指定的多个文件名作为一个长的连续的输入流。
而GNU sed则允许把他们当作单独的文件,
这样如正则表达式则不进行跨文件匹配。
-u, --unbuffered 最低限度的缓存输入与输出。
2.简单案例:
以上仅是sed程序本身的选项功能说明,至于具体的脚本指令(即对文件内容做的操作)后面我们会详细描述,
这里就简单介绍几个脚本指令操作作为sed程序的例子。
a,append 追加
i,insert 插入
d,delete 删除
s,substitution 替换
案例说明:灰色背景的内容为待处理的源文件,红色字体的文字为sed脚本,蓝色字体的文字为处理后的结果输出。
这里test.txt为样本文件:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
[jacob@localhost ~] #sed '2a TYPE=Ethernet' test.txt 第二行后添加TYPE=Ethernet
[jacob@localhost ~] #sed '3i TYPE=Ethernet' test.txt 第三行前添加TYPE=Ethernet
[jacob@localhost ~] #sed 's/yes/no/g' test.txt 将样本文件中的所有yes替换为no
[jacob@localhost ~] #sed '3,4d' test.txt 删除第3至4行的内容
以上大多数操作指令,都依据行号定位操作对象(地址),如:2a即第二行后添加。
但实际情况可能大多数情况你并不确定你要操作对象(地址)的行号,这时更多的我们会使用正则表达式确定操作对象(地址)。
下面是使用正则表达式定位操作行的示例:
[jacob@localhost ~] #sed '/ONBOOT/a TYPE=Ethernet' test.txt
匹配到包含ONBOOT的行,并在其后添加TYPE=Ethernet
[jacob@localhost ~] #sed '/^GATEWAY/d' test.txt
匹配以GATEWAY开始的行,并删除改行
另外我们的操作指令可以,写入到脚本文件中并通过sed的-f选项读取。
创建一个sed脚本,内容如下:
[jacob@localhost ~] #cat sed.sh
/^$/d 这条指令的作用是:匹配到空白行后,删除改行。
[jacob@localhost ~] #sed -f sed.sh test.txt 对test.txt文件执行sed.sh指令
另外,当你需要执行多个指令时,可以使用以下三种方法:
1. [jacob@localhost ~] #sed 's/yes/no/;s/static/dhcp/' test.txt 注:使用分号隔开指令。
2. [jacob@localhost ~] #sed -e 's/yes/no/' -e 's/static/dhcp/' test.txt 注:使用-e选项。
3. [jacob@localhost ~] #sed '
>s/yes/no/
>s/static/dhcp/' test.txt 注:利用分行指令。
然而在命令行上输入过长的指令是愚蠢的,这时就需要-f选项指定sed脚本文件,在脚本文件中可以包含多行指令,而且便于修改!
*****************************************************************************************
三、简单正则表达式
从以上案例中我们不难发现,我们编写的脚本指令需要指定一个地址来决定操作范围,如果不指定则默认对文件的所有行操作。
如:sed 'd' test.txt 将删除test.txt的所有行,而'2d'则仅删除第二行。
1.为sed指令确定操作地址:
number 指定输入文件的唯一行号。
first~step 以first开始,并指定操作步长为step,如1~2,指定第一行,第三行,第五行... 为操作地址。
[jacob@localhost ~] #sed -n '1~2p' test.txt 打印文件的奇数行。
2~5,则可以指定第二行开始,每5行匹配一次操作地址。
$ 匹配文件的最后一行。
/regexp/ //中间包含的是正则表达式,通过正则表达式匹配操作地址。
注://空的正则表达式,匹配最近一次正则表达式的匹配地址,会在后面使用看出效果。
\cregexpc 匹配扩展正则表达式,c字符可以使用任意字符替代。
addr1,addr2 匹配从操作地址1到操作地址2的所有行。
[jacob@localhost ~] #sed '2,8d' test.txt 删除2至8中间的所有行。
addr1,+N 匹配地址1以及后面的N行内容。
2.正则表达式概述(对你要找内容的一种描述)
char 字符本身就匹配字符本身,如/abc/就是定位包含abc的行。
* 匹配前面表达式出现了0或若干次,如/a*/可以帮你找到a,aa,aaa,... ...等等。
\+ 类似于*,但匹配前面表达式的1次或多次,这属于扩展正则表达式。
\? 类似于*,但匹配前面表达式的0次或1次,这属于扩展正则表达式。
\{i\} 类似于*,但匹配前面表达式的i次(i为整数),如:a\{3\}可以帮你找到aaa。
\{i,j\} 匹配前面表达式的i到j次,如a\{1,2\}可以帮你找到a或aa或aaa。
\{i,\} 匹配前面表达式至少i次。
\( \) 将\( \)内的模式存储在保留空间。最多可以存储9个独立子模式,可
通过转义\1至\9重复保留空间的内容至此点。
\n 转义\1至\9重复保留空间的内容至此点。
例:test.txt的内容为ssttss
grep '\(ss\)tt\1' test.txt \1表示将ss重复在tt后面
该grep命令等同于grep ssttss test.txt 在test.txt文件中找ssttss
. (点)匹配任意字符。
^ 匹配行的开始,如^test 将匹配所有以test开始的行。
$ 匹配行的结尾,如test$ 将匹配所有以test结尾的行。
[] 匹配括号中的任意单个字符,如a[nt] 将匹配an或at。
[^] 匹配不包含在[]中的字符,如[^a-z] 将匹配除a-z以外的字符。
\n 匹配换行符。
\char 转义特殊字符,如\*,就是匹配字面意义上的星号。
**************************************************************************************
四、sed脚本指令
常用的sed脚本指令有:
*注释(#)
*替换(s)
*删除(d)
*追加(a)
*插入(i)
*更改(c)
*列印(l)
*转换(y)
*打印(p)
*读写文件(r,w)
*退出(q)
*下一步(n)
*Next(N)
*Print(P)
*Delete(D)
*Hold(h,H)
*Get(g,G)
*branch,test
sed脚本指令的基本格式:
[address]command
[地址]命令 备注:有些命令仅可以对一行操作,有些可以对多行操作。
命令可以用大括号进行组合以使命令序列可以作用于同一个地址:
address{
command1
command2
command3
}
第一个命令可以和左大括号在同一行,但右大括号必须单独处于一行。
注意事项:命令后添加空格会产生错误。
1.注释(#):
注释行是以#开始的行,如果#后面的字符为n,则屏蔽sed程序的自动输出功能,等同于命令选项-n。
2.替换(s,Substitution):
[address]s/pattern/replacement/flags
address为操作地址,s为替换指令,/pattern/匹配要替换的内容,/replacement/为替换的内容。
flags可以是:
n 1至512之间的数字,表示对模式空中指定模式的第n次出现进行替换。
如一行中有3个A,而只想替换第二个A。
g 对模式空间的匹配进行全局更改。没有g则仅第一次匹配被替换,如一行中有3个A,则仅替换第一个A。
p 打印模式空间的内容。
w file
将模式空间的内容写到文件file中。
replacement为字符串,用来替换与正则表达式匹配的内容。
在replacement部分,只有下列字符有特殊含义:
& 用正则表达式匹配的内容进行替换。
\n 匹配第n个子串,这个子串之前在pattern中用\( \)指定。
\ 转义(转义替换部分包含的:&, \等)。
-----------------------------------------------------------------------------------------------
示例1所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
<html>
<title>First Web</title>
<body>Hello the World! <body>
</html>
示例1:将样本文件中的第二个<body>替换为</body>
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/body/{
s//\/body/2 注:替换与行匹配相同的内容即body,替换为/body,但仅替换第二个body为/body。
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
<html>
<title>First Web</title>
<body>Hello the World!</body>
</html>
---------------------------------------------------------------------------------------------
示例2所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
<html>
<title>First Web</title>
<body>
h1Helloh1
h2Helloh2
h3Helloh3
</body>
</html>
示例2:给所有第一个的h1,h2等添加<>;第二个h1,h2添加</>
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/h[0-9]/{ 注:匹配h紧跟一个数字的行
s//\<&\>/1 注:替换与上一行中匹配内容相同的内容,即替换h[0-9],替换为<&>,其中&即前面要替换的内容。
s//\<\/&\>/2 注:上一条指令仅替换第一个h1,h2...,本行指令用来替换第二个h1,h2...。
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
<h1>Hello</h1>
<h2>Hello</h2>
<h3>Hello</h3>
---------------------------------------------------------------------------------------------
技巧:关于 's///' 命令的另一个妙处是 '/' 分隔符有许多替换选项。
如果规则表达式或替换字符串中有许多斜杠,则可以通过在 's' 之后指定一个不同的字符来更改分隔符。
示例:$ sed -e 's:/usr/local:/usr:g' mylist.txt 这里:为分隔符。
3.删除(d ,delete):
删除指令删除匹配的行,而且删除命令还会改变sed脚本中命令的执行顺序。因为:
匹配的行一旦被删除,模式空间将变为“空”,自然不会再执行sed脚本后续的命令。
删除命令将导致读取新的输入行(下一行),而sed脚本中的命令则从头开始执行。
注意事项:删除将删除整个行,而不只是删除匹配的内容。(如要删除匹配的内容,可以使用替换)
示例1所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
示例1:删除文件中的空白行
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
/^$/d
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
4.追加(a):在匹配行后追加内容
示例所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
示例程序:sed '/static/a IPADDR=192.168.0.1' test.txt 注:在static行后添加一行。
5.插入(i):在匹配行前插入内容
示例程序:sed '/NETMASK/i IPADDR=192.168.0.1' test.txt 注:在NETMASK行前添加一行。
6.更改(c):更改匹配行的内容
示例程序:sed '/ONBOOT/c ONBOOT=yes' test.txt 注:包含ONBOOT的行(整行)替换为ONBOOT=yes。
7.列印(l):显示模式空间中的内容,显示非打印字符,一般与-n一起使用,否则会输出两次。
示例程序:sed -n '1,2l' test.txt 注:如果使用sed脚本文件,需要#n屏蔽自动输出
结果如下:
DEVICE=eth0$
ONBOOT=yes$
8.转换(y):按字符的转换(Transform) [address]y/source-chars/dest-chars/
示例所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
netmask=255.255.255.0
GATEWAY=192.168.0.254
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
/netmask/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ 将小写转换为大写
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
9.打印(p):作用类似与l(列印),但不显示非显示字符,一般与-n配合使用,脚本文件中需要#n
sed -n '1,2p' test.txt 仅显示第一、第二行的内容。
10.读写文件(r,w):[line-address]r file, [address]w file
示例所使用的样本文件为:
[jacob@localhost ~] #cat name.txt
Jacob
Tom
Jerry
[jacob@localhost ~] #cat mail.txt
jacob@gmail.com
tom@gmail.com
jerry@gmail.com
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
$r mail.txt
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh name.txt
Jacob
Tom
Jerry
jacob@gmail.com
tom@gmail.com
jerry@gmail.com
11.退出(q): 匹配地址后退出sed脚本
sed '10q' test.txt 打印文件前10行内容(到第10行后退出sed脚本指令)。
12.下一步(n): [address]n 输出模式空间中的内容,然后读取输入的下一行。
next命令改变了正常的sed脚本指令的流程,默认只有到sed脚本的底部才会输出模式空间的内容。
next命令导致输入的下一行取代模式空间中的当前行,sed脚本中的后续命令将应用于替换后的行,而不是当前行。
示例所使用的样本文件为:
[jacob@localhost ~] #cat name.txt
Jacob
Tom
Jerry
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
n 读取下一行后删除(删除偶数行)。
/.*/d
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh name.txt
Jacob
Jerry
13.Next(N):
多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后,来创建多行模式空间。
模式空间的最初内容与新的输入行之间用换行符分隔。在模式空间中插入的换行符可以使用\n匹配。
示例1:
[jacob@localhost ~] #cat test.txt
111
222
222
333
[jacob@localhost ~] #cat sed.sh
#n
/222/{
N
l
}
[jacob@localhost ~] #sed -f sed.sh test.txt 结果如下:
222\n222
示例2:
[jacob@localhost ~] #cat test.txt
111
222
222
222
333
[jacob@localhost ~] #cat sed.sh
#n
/222/{
N
l
}
[jacob@localhost ~] #sed -f sed.sh test.txt
222\n222
222\n333
14.Print(P):多行打印(P)与打印(p)稍有不同,该命令仅输出多行模式空间中的第一部分,直到第一个插入的\n换行符为止。
示例:
#cat test.txt #cat test.txt #cat test.txt #cat test.txt
111 111 111 111
222 222 222 222
333 333 333 333
444 444 444 444
555 555 555 555
666 666 666 666
-----------------------------------------------------------------------------------------------------
#cat sed.sh #cat sed.sh #cat sed.sh #cat sed.sh
/.*/{ /.*/{ /.*/{ /.*/{
N N N N
} l P p
} } }
------------------------------------------------------------------------------------------------------
结果: 结果: 结果: 结果:
111 111\n222$ 111 111
222 111 111 222
333 222 222 111
444 333\n444$ 333 222
555 333 333 333
666 444 444 444
555\n666$ 555 333
555 555 444
666 666 555
666
555
666
-------------------------------------------------------------------------------------------------------
流程说明:1.sed脚本文件使用了N,但后续没有任何指令,所以仅按sed自动输出,即输出源文件所有内容。
2.sed脚本问使用了N,l表示显示模式空间的内容,即111\n222(N的作用为把下一行追加至行尾),
同时sed脚本的自动输出功能会把源文件内容显示出来即111,222。
依次类推,sed脚本继续读取第三行333,并使用N将444追加至行尾,使用l显示模式空间的内容,
sed自动输出再把源文件内容显示出来。
3.sed脚本文件使用了N将下一行追加至行尾,现在模式空间中的内容为111\n222,而P指令的作用是
打印模式空间中的第一部分内容直到\n结尾,即仅打印111,这时sed的自动输出功能把源文件
内容打印出来111,222。依次类推读取第三行333,N将444追加至行尾,P打印\n前的内容,
同时sed脚本自动将源问内容输出。
4.原理类似与第三个sed脚本,但p打印时\n看作是回车换行,所以打印出来的是111回车222。
-----------------------------------------------------------------------------------------------------
15.Delete(D):
删除命令(d)删除模式空间中的内容并导致读入新的输入行,而sed脚本重新执行。
删除命令(D)删除模式空间中直到第一个插入的换行符(\n)前的这部分内容,它不会读入新的输入行,并返回sed脚本的顶端,
使得剩余指令继续应用于模式空间中剩余的内容。
16.Hold(h,H),Get(g,G):
模式空间是存放当前输入行的缓冲区。还有一个称为保持空间(hold space)的缓冲区。
模式空间的内容可以复制到保持空间,保持空间的内容同样可以复制到模式空间。
有一组命令用于在两者之间移动数据。
Hold(h|H) 将模式空间的内容复制或追加到保持空间
Get(g|G) 将保持空间的内容复制或追加到模式空间
Exchange(x) 交换保持空间与模式空间的内容
示例:反转部分行
[jacob@localhost ~] #cat test.txt
1
2
11
22
111
222
[jacob@localhost ~] #cat sed.sh
/1/{
h
d
}
/2/{
G
}
结果:
2
1
22
11
222
111
17.branch,test
分支(b),测试(t)命令将sed脚本中的控制转移到包含特殊标签的行,如果没有指定的标签,则将控制转移到脚本结尾处。
分支命令是无条件转移,测试命令用于有条件转移,测试只有当替换命令改变当前行成功时才会执行。
标签是任意不多于7个字符的序列,标签本身占据一行并以冒号开始:
:mylable
冒号与标签之间不允许有空格
当分支或测试命令中指定标签时,在命令与标签之间允许有空格:
b mylabel 注:不要在标签后插入空格
五、综合案例(案例摘自GNU sed官网)
综合案例1:重命名文件名为小写
[jacob@localhost ~] #cat sed.sh
#! /bin/sh
# rename files to lower/upper case...
#
# usage:
# move-to-lower *
# move-to-upper *
# or
# move-to-lower -R .
# move-to-upper -R .
#
help()
{
cat << eof
Usage: $0 [-n] [-r] [-h] files...
-n do nothing, only see what would be done
-R recursive (use find)
-h this message
files files to remap to lower case
Examples:
$0 -n * (see if everything is ok, then...)
$0 *
$0 -R .
eof
}
apply_cmd='sh'
finder='echo "$@" | tr " " "\n"'
files_only=
while :
do
case "$1" in
-n) apply_cmd='cat' ;;
-R) finder='find "$@" -type f';;
-h) help ; exit 1 ;;
*) break ;;
esac
shift
done
if [ -z "$1" ]; then
echo Usage: $0 [-h] [-n] [-r] files...
exit 1
fi
LOWER='abcdefghijklmnopqrstuvwxyz'
UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
case `basename $0` in
*upper*) TO=$UPPER; FROM=$LOWER ;;
*) FROM=$UPPER; TO=$LOWER ;;
esac
eval $finder | sed -n '
# remove all trailing slashes
s/\/*$//
# add ./ if there is no path, only a filename
/\//! s/^/.\//
# save path+filename
h
# remove path
s/.*\///
# do conversion only on filename
y/'$FROM'/'$TO'/
# now line contains original path+file, while
# hold space contains the new filename
x
# add converted file name to line, which now contains
# path/file-name\nconverted-file-name
G
# check if converted file name is equal to original file name,
# if it is, do not print nothing
/^.*\/\(.*\)\n\1/b
# now, transform path/fromfile\n, into
# mv path/fromfile path/tofile and print it
s/^\(.*\/\)\(.*\)\n\(.*\)$/mv "\1\2" "\1\3"/p
' | $apply_cmd
综合案例2:获取bash环境变量
#!/bin/sh
set | sed -n '
# if no occurrence of ‘=()’ print and load next line
/=()/! { p; b; }
/ () $/! { p; b; }
# possible start of functions section
# save the line in case this is a var like FOO="() "
h
# if the next line has a brace, we quit because
# nothing comes after functions
n
/^{/ q
# print the old line
x; p
# work on the new line now
x; bx
'
http://manual.blog.51cto.com/3300438/908002
目录:
一、概述
二、sed基本语法格式
三、简单正则表达式
四、sed脚本指令(注释、替换、删除、追加、打印、下一行、读写文件、退出、多行模式)
五、综合案例
一、概述
1.sed是一款流编辑工具,用来对文本进行过滤与替换工作,特别是当你想要对几十个配置文件做统计修改时,你会感受到sed的魅力!
sed通过输入读取文件内容,但一次仅读取一行内容进行某些指令处理后输出,所以sed更适合于处理大数据文件。
2.sed流程:
* 通过文件或管道读取文件内容。
* sed并不直接修改源文件,而是将读入的内容复制到缓冲区中,我们称之为模式空间(pattern space)。
* 根据sed的指令对模式空间中的内容进行处理并输出结果,默认输出至标准输出即屏幕上。
输入
------------------------------------------------
|
|
v
v
读取一行内容,并复制到模式空间 <------------ sed 指令
|
|
v
v
------------------------------------------------
输出经过处理后的内容
*****************************************************************************************************
二、sed基本语法结构
sed Options... [script] [inputfile...]
sed 选项... [脚本指令] [输入文件]
如果没有输入文件,则sed默认对标准输入进行处理(即键盘输入)。脚本指令是第一个不以“-”开始的参数。
1.选项含义:
--version 显示sed版本。
--help 显示帮助文档。
-n,--quiet,--silent 静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印
模式空间中的内容,这些选项可以屏蔽自动打印。
-e script 允许多个脚本指令被执行。
-f script-file,
--file=script-file 从文件中读取脚本指令,对编写自动脚本程序来说很棒!
-i,--in-place 直接修改源文件,经过脚本指令处理后的内容将被输出至源文件(源文件被修改)
慎用!
-l N, --line-length=N 该选项指定l指令可以输出的行长度,l指令用于输出非打印字符。
--posix 禁用GNU sed扩展功能。
-r, --regexp-extended
在脚本指令中使用扩展正则表达式
-s, --separate 默认情况下,sed将把命令行指定的多个文件名作为一个长的连续的输入流。
而GNU sed则允许把他们当作单独的文件,
这样如正则表达式则不进行跨文件匹配。
-u, --unbuffered 最低限度的缓存输入与输出。
2.简单案例:
以上仅是sed程序本身的选项功能说明,至于具体的脚本指令(即对文件内容做的操作)后面我们会详细描述,
这里就简单介绍几个脚本指令操作作为sed程序的例子。
a,append 追加
i,insert 插入
d,delete 删除
s,substitution 替换
案例说明:灰色背景的内容为待处理的源文件,红色字体的文字为sed脚本,蓝色字体的文字为处理后的结果输出。
这里test.txt为样本文件:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
[jacob@localhost ~] #sed '2a TYPE=Ethernet' test.txt 第二行后添加TYPE=Ethernet
[jacob@localhost ~] #sed '3i TYPE=Ethernet' test.txt 第三行前添加TYPE=Ethernet
[jacob@localhost ~] #sed 's/yes/no/g' test.txt 将样本文件中的所有yes替换为no
[jacob@localhost ~] #sed '3,4d' test.txt 删除第3至4行的内容
以上大多数操作指令,都依据行号定位操作对象(地址),如:2a即第二行后添加。
但实际情况可能大多数情况你并不确定你要操作对象(地址)的行号,这时更多的我们会使用正则表达式确定操作对象(地址)。
下面是使用正则表达式定位操作行的示例:
[jacob@localhost ~] #sed '/ONBOOT/a TYPE=Ethernet' test.txt
匹配到包含ONBOOT的行,并在其后添加TYPE=Ethernet
[jacob@localhost ~] #sed '/^GATEWAY/d' test.txt
匹配以GATEWAY开始的行,并删除改行
另外我们的操作指令可以,写入到脚本文件中并通过sed的-f选项读取。
创建一个sed脚本,内容如下:
[jacob@localhost ~] #cat sed.sh
/^$/d 这条指令的作用是:匹配到空白行后,删除改行。
[jacob@localhost ~] #sed -f sed.sh test.txt 对test.txt文件执行sed.sh指令
另外,当你需要执行多个指令时,可以使用以下三种方法:
1. [jacob@localhost ~] #sed 's/yes/no/;s/static/dhcp/' test.txt 注:使用分号隔开指令。
2. [jacob@localhost ~] #sed -e 's/yes/no/' -e 's/static/dhcp/' test.txt 注:使用-e选项。
3. [jacob@localhost ~] #sed '
>s/yes/no/
>s/static/dhcp/' test.txt 注:利用分行指令。
然而在命令行上输入过长的指令是愚蠢的,这时就需要-f选项指定sed脚本文件,在脚本文件中可以包含多行指令,而且便于修改!
*****************************************************************************************
三、简单正则表达式
从以上案例中我们不难发现,我们编写的脚本指令需要指定一个地址来决定操作范围,如果不指定则默认对文件的所有行操作。
如:sed 'd' test.txt 将删除test.txt的所有行,而'2d'则仅删除第二行。
1.为sed指令确定操作地址:
number 指定输入文件的唯一行号。
first~step 以first开始,并指定操作步长为step,如1~2,指定第一行,第三行,第五行... 为操作地址。
[jacob@localhost ~] #sed -n '1~2p' test.txt 打印文件的奇数行。
2~5,则可以指定第二行开始,每5行匹配一次操作地址。
$ 匹配文件的最后一行。
/regexp/ //中间包含的是正则表达式,通过正则表达式匹配操作地址。
注://空的正则表达式,匹配最近一次正则表达式的匹配地址,会在后面使用看出效果。
\cregexpc 匹配扩展正则表达式,c字符可以使用任意字符替代。
addr1,addr2 匹配从操作地址1到操作地址2的所有行。
[jacob@localhost ~] #sed '2,8d' test.txt 删除2至8中间的所有行。
addr1,+N 匹配地址1以及后面的N行内容。
2.正则表达式概述(对你要找内容的一种描述)
char 字符本身就匹配字符本身,如/abc/就是定位包含abc的行。
* 匹配前面表达式出现了0或若干次,如/a*/可以帮你找到a,aa,aaa,... ...等等。
\+ 类似于*,但匹配前面表达式的1次或多次,这属于扩展正则表达式。
\? 类似于*,但匹配前面表达式的0次或1次,这属于扩展正则表达式。
\{i\} 类似于*,但匹配前面表达式的i次(i为整数),如:a\{3\}可以帮你找到aaa。
\{i,j\} 匹配前面表达式的i到j次,如a\{1,2\}可以帮你找到a或aa或aaa。
\{i,\} 匹配前面表达式至少i次。
\( \) 将\( \)内的模式存储在保留空间。最多可以存储9个独立子模式,可
通过转义\1至\9重复保留空间的内容至此点。
\n 转义\1至\9重复保留空间的内容至此点。
例:test.txt的内容为ssttss
grep '\(ss\)tt\1' test.txt \1表示将ss重复在tt后面
该grep命令等同于grep ssttss test.txt 在test.txt文件中找ssttss
. (点)匹配任意字符。
^ 匹配行的开始,如^test 将匹配所有以test开始的行。
$ 匹配行的结尾,如test$ 将匹配所有以test结尾的行。
[] 匹配括号中的任意单个字符,如a[nt] 将匹配an或at。
[^] 匹配不包含在[]中的字符,如[^a-z] 将匹配除a-z以外的字符。
\n 匹配换行符。
\char 转义特殊字符,如\*,就是匹配字面意义上的星号。
**************************************************************************************
四、sed脚本指令
常用的sed脚本指令有:
*注释(#)
*替换(s)
*删除(d)
*追加(a)
*插入(i)
*更改(c)
*列印(l)
*转换(y)
*打印(p)
*读写文件(r,w)
*退出(q)
*下一步(n)
*Next(N)
*Print(P)
*Delete(D)
*Hold(h,H)
*Get(g,G)
*branch,test
sed脚本指令的基本格式:
[address]command
[地址]命令 备注:有些命令仅可以对一行操作,有些可以对多行操作。
命令可以用大括号进行组合以使命令序列可以作用于同一个地址:
address{
command1
command2
command3
}
第一个命令可以和左大括号在同一行,但右大括号必须单独处于一行。
注意事项:命令后添加空格会产生错误。
1.注释(#):
注释行是以#开始的行,如果#后面的字符为n,则屏蔽sed程序的自动输出功能,等同于命令选项-n。
2.替换(s,Substitution):
[address]s/pattern/replacement/flags
address为操作地址,s为替换指令,/pattern/匹配要替换的内容,/replacement/为替换的内容。
flags可以是:
n 1至512之间的数字,表示对模式空中指定模式的第n次出现进行替换。
如一行中有3个A,而只想替换第二个A。
g 对模式空间的匹配进行全局更改。没有g则仅第一次匹配被替换,如一行中有3个A,则仅替换第一个A。
p 打印模式空间的内容。
w file
将模式空间的内容写到文件file中。
replacement为字符串,用来替换与正则表达式匹配的内容。
在replacement部分,只有下列字符有特殊含义:
& 用正则表达式匹配的内容进行替换。
\n 匹配第n个子串,这个子串之前在pattern中用\( \)指定。
\ 转义(转义替换部分包含的:&, \等)。
-----------------------------------------------------------------------------------------------
示例1所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
<html>
<title>First Web</title>
<body>Hello the World! <body>
</html>
示例1:将样本文件中的第二个<body>替换为</body>
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/body/{
s//\/body/2 注:替换与行匹配相同的内容即body,替换为/body,但仅替换第二个body为/body。
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
<html>
<title>First Web</title>
<body>Hello the World!</body>
</html>
---------------------------------------------------------------------------------------------
示例2所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
<html>
<title>First Web</title>
<body>
h1Helloh1
h2Helloh2
h3Helloh3
</body>
</html>
示例2:给所有第一个的h1,h2等添加<>;第二个h1,h2添加</>
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/h[0-9]/{ 注:匹配h紧跟一个数字的行
s//\<&\>/1 注:替换与上一行中匹配内容相同的内容,即替换h[0-9],替换为<&>,其中&即前面要替换的内容。
s//\<\/&\>/2 注:上一条指令仅替换第一个h1,h2...,本行指令用来替换第二个h1,h2...。
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
<h1>Hello</h1>
<h2>Hello</h2>
<h3>Hello</h3>
---------------------------------------------------------------------------------------------
技巧:关于 's///' 命令的另一个妙处是 '/' 分隔符有许多替换选项。
如果规则表达式或替换字符串中有许多斜杠,则可以通过在 's' 之后指定一个不同的字符来更改分隔符。
示例:$ sed -e 's:/usr/local:/usr:g' mylist.txt 这里:为分隔符。
3.删除(d ,delete):
删除指令删除匹配的行,而且删除命令还会改变sed脚本中命令的执行顺序。因为:
匹配的行一旦被删除,模式空间将变为“空”,自然不会再执行sed脚本后续的命令。
删除命令将导致读取新的输入行(下一行),而sed脚本中的命令则从头开始执行。
注意事项:删除将删除整个行,而不只是删除匹配的内容。(如要删除匹配的内容,可以使用替换)
示例1所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
示例1:删除文件中的空白行
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
/^$/d
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
4.追加(a):在匹配行后追加内容
示例所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
示例程序:sed '/static/a IPADDR=192.168.0.1' test.txt 注:在static行后添加一行。
5.插入(i):在匹配行前插入内容
示例程序:sed '/NETMASK/i IPADDR=192.168.0.1' test.txt 注:在NETMASK行前添加一行。
6.更改(c):更改匹配行的内容
示例程序:sed '/ONBOOT/c ONBOOT=yes' test.txt 注:包含ONBOOT的行(整行)替换为ONBOOT=yes。
7.列印(l):显示模式空间中的内容,显示非打印字符,一般与-n一起使用,否则会输出两次。
示例程序:sed -n '1,2l' test.txt 注:如果使用sed脚本文件,需要#n屏蔽自动输出
结果如下:
DEVICE=eth0$
ONBOOT=yes$
8.转换(y):按字符的转换(Transform) [address]y/source-chars/dest-chars/
示例所使用的样本文件为:
[jacob@localhost ~] #cat test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
netmask=255.255.255.0
GATEWAY=192.168.0.254
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
/netmask/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ 将小写转换为大写
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh test.txt
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=static
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
9.打印(p):作用类似与l(列印),但不显示非显示字符,一般与-n配合使用,脚本文件中需要#n
sed -n '1,2p' test.txt 仅显示第一、第二行的内容。
10.读写文件(r,w):[line-address]r file, [address]w file
示例所使用的样本文件为:
[jacob@localhost ~] #cat name.txt
Jacob
Tom
Jerry
[jacob@localhost ~] #cat mail.txt
jacob@gmail.com
tom@gmail.com
jerry@gmail.com
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
$r mail.txt
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh name.txt
Jacob
Tom
Jerry
jacob@gmail.com
tom@gmail.com
jerry@gmail.com
11.退出(q): 匹配地址后退出sed脚本
sed '10q' test.txt 打印文件前10行内容(到第10行后退出sed脚本指令)。
12.下一步(n): [address]n 输出模式空间中的内容,然后读取输入的下一行。
next命令改变了正常的sed脚本指令的流程,默认只有到sed脚本的底部才会输出模式空间的内容。
next命令导致输入的下一行取代模式空间中的当前行,sed脚本中的后续命令将应用于替换后的行,而不是当前行。
示例所使用的样本文件为:
[jacob@localhost ~] #cat name.txt
Jacob
Tom
Jerry
编写sed脚本为:
[jacob@localhost ~] #cat sed.sh
/.*/{
n 读取下一行后删除(删除偶数行)。
/.*/d
}
执行sed程序的结果:
[jacob@localhost ~] #sed -f sed.sh name.txt
Jacob
Jerry
13.Next(N):
多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后,来创建多行模式空间。
模式空间的最初内容与新的输入行之间用换行符分隔。在模式空间中插入的换行符可以使用\n匹配。
示例1:
[jacob@localhost ~] #cat test.txt
111
222
222
333
[jacob@localhost ~] #cat sed.sh
#n
/222/{
N
l
}
[jacob@localhost ~] #sed -f sed.sh test.txt 结果如下:
222\n222
示例2:
[jacob@localhost ~] #cat test.txt
111
222
222
222
333
[jacob@localhost ~] #cat sed.sh
#n
/222/{
N
l
}
[jacob@localhost ~] #sed -f sed.sh test.txt
222\n222
222\n333
14.Print(P):多行打印(P)与打印(p)稍有不同,该命令仅输出多行模式空间中的第一部分,直到第一个插入的\n换行符为止。
示例:
#cat test.txt #cat test.txt #cat test.txt #cat test.txt
111 111 111 111
222 222 222 222
333 333 333 333
444 444 444 444
555 555 555 555
666 666 666 666
-----------------------------------------------------------------------------------------------------
#cat sed.sh #cat sed.sh #cat sed.sh #cat sed.sh
/.*/{ /.*/{ /.*/{ /.*/{
N N N N
} l P p
} } }
------------------------------------------------------------------------------------------------------
结果: 结果: 结果: 结果:
111 111\n222$ 111 111
222 111 111 222
333 222 222 111
444 333\n444$ 333 222
555 333 333 333
666 444 444 444
555\n666$ 555 333
555 555 444
666 666 555
666
555
666
-------------------------------------------------------------------------------------------------------
流程说明:1.sed脚本文件使用了N,但后续没有任何指令,所以仅按sed自动输出,即输出源文件所有内容。
2.sed脚本问使用了N,l表示显示模式空间的内容,即111\n222(N的作用为把下一行追加至行尾),
同时sed脚本的自动输出功能会把源文件内容显示出来即111,222。
依次类推,sed脚本继续读取第三行333,并使用N将444追加至行尾,使用l显示模式空间的内容,
sed自动输出再把源文件内容显示出来。
3.sed脚本文件使用了N将下一行追加至行尾,现在模式空间中的内容为111\n222,而P指令的作用是
打印模式空间中的第一部分内容直到\n结尾,即仅打印111,这时sed的自动输出功能把源文件
内容打印出来111,222。依次类推读取第三行333,N将444追加至行尾,P打印\n前的内容,
同时sed脚本自动将源问内容输出。
4.原理类似与第三个sed脚本,但p打印时\n看作是回车换行,所以打印出来的是111回车222。
-----------------------------------------------------------------------------------------------------
15.Delete(D):
删除命令(d)删除模式空间中的内容并导致读入新的输入行,而sed脚本重新执行。
删除命令(D)删除模式空间中直到第一个插入的换行符(\n)前的这部分内容,它不会读入新的输入行,并返回sed脚本的顶端,
使得剩余指令继续应用于模式空间中剩余的内容。
16.Hold(h,H),Get(g,G):
模式空间是存放当前输入行的缓冲区。还有一个称为保持空间(hold space)的缓冲区。
模式空间的内容可以复制到保持空间,保持空间的内容同样可以复制到模式空间。
有一组命令用于在两者之间移动数据。
Hold(h|H) 将模式空间的内容复制或追加到保持空间
Get(g|G) 将保持空间的内容复制或追加到模式空间
Exchange(x) 交换保持空间与模式空间的内容
示例:反转部分行
[jacob@localhost ~] #cat test.txt
1
2
11
22
111
222
[jacob@localhost ~] #cat sed.sh
/1/{
h
d
}
/2/{
G
}
结果:
2
1
22
11
222
111
17.branch,test
分支(b),测试(t)命令将sed脚本中的控制转移到包含特殊标签的行,如果没有指定的标签,则将控制转移到脚本结尾处。
分支命令是无条件转移,测试命令用于有条件转移,测试只有当替换命令改变当前行成功时才会执行。
标签是任意不多于7个字符的序列,标签本身占据一行并以冒号开始:
:mylable
冒号与标签之间不允许有空格
当分支或测试命令中指定标签时,在命令与标签之间允许有空格:
b mylabel 注:不要在标签后插入空格
五、综合案例(案例摘自GNU sed官网)
综合案例1:重命名文件名为小写
[jacob@localhost ~] #cat sed.sh
#! /bin/sh
# rename files to lower/upper case...
#
# usage:
# move-to-lower *
# move-to-upper *
# or
# move-to-lower -R .
# move-to-upper -R .
#
help()
{
cat << eof
Usage: $0 [-n] [-r] [-h] files...
-n do nothing, only see what would be done
-R recursive (use find)
-h this message
files files to remap to lower case
Examples:
$0 -n * (see if everything is ok, then...)
$0 *
$0 -R .
eof
}
apply_cmd='sh'
finder='echo "$@" | tr " " "\n"'
files_only=
while :
do
case "$1" in
-n) apply_cmd='cat' ;;
-R) finder='find "$@" -type f';;
-h) help ; exit 1 ;;
*) break ;;
esac
shift
done
if [ -z "$1" ]; then
echo Usage: $0 [-h] [-n] [-r] files...
exit 1
fi
LOWER='abcdefghijklmnopqrstuvwxyz'
UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
case `basename $0` in
*upper*) TO=$UPPER; FROM=$LOWER ;;
*) FROM=$UPPER; TO=$LOWER ;;
esac
eval $finder | sed -n '
# remove all trailing slashes
s/\/*$//
# add ./ if there is no path, only a filename
/\//! s/^/.\//
# save path+filename
h
# remove path
s/.*\///
# do conversion only on filename
y/'$FROM'/'$TO'/
# now line contains original path+file, while
# hold space contains the new filename
x
# add converted file name to line, which now contains
# path/file-name\nconverted-file-name
G
# check if converted file name is equal to original file name,
# if it is, do not print nothing
/^.*\/\(.*\)\n\1/b
# now, transform path/fromfile\n, into
# mv path/fromfile path/tofile and print it
s/^\(.*\/\)\(.*\)\n\(.*\)$/mv "\1\2" "\1\3"/p
' | $apply_cmd
综合案例2:获取bash环境变量
#!/bin/sh
set | sed -n '
# if no occurrence of ‘=()’ print and load next line
/=()/! { p; b; }
/ () $/! { p; b; }
# possible start of functions section
# save the line in case this is a var like FOO="() "
h
# if the next line has a brace, we quit because
# nothing comes after functions
n
/^{/ q
# print the old line
x; p
# work on the new line now
x; bx
'
http://manual.blog.51cto.com/3300438/908002
发表评论
-
ZT Expect语法
2014-03-02 20:29 323正在学习中... 1.[摘要] ... -
ZT Shell调试篇
2014-02-21 21:14 372检查语法 -n选项只做语法检查,而不执行脚本。 sh ... -
ZT shell经典,shell十三问
2014-02-21 21:13 330我在 CU 的日子并不长,有幸在 shell 版上与大家结缘 ... -
ZT linux shell中 if else以及大于、小于、等于逻辑表达式介绍
2014-02-21 21:02 634linux shell中 if else以及 ... -
ZT SHELL脚本编程的常识
2014-02-21 21:01 449SHELL脚本编程的常识 七种文件类型 正则表达式 ... -
ZT shell if
2014-02-21 20:57 415if 语句格式 if 条件then Command ... -
zz SHELL脚本编程的常识
2014-01-04 19:44 684SHELL脚本编程的常识 七种文件类型 正则表达式 字符类描述 ...
相关推荐
shell编程中经常用到sed命令,本文详细介绍了shell常用命令sed详细用法
NULL 博文链接:https://ginge.iteye.com/blog/465063
Shell脚本专家指南.pdf sed与awk第二版.pdf shell十三问.pdf
shell脚本修改json中某个字段的值 - 思路:通过awk来找到旧数据,然后用sed来替换旧数据
本文主要是对linux-shell脚本命令中的sed命令进行简单介绍。
《Shell脚本专家指南》旨在为Linux、Unix以及OSx系统管理员提供短小精悍且功能强大的shell实现解决方案,教会读者如何使用现有调试器调试shell脚本。全书分为3个部分:脚本技术基础、系统交互和高级技术、有用的脚本...
shell编程,sed,awk,grep等教程
shell脚本学习资料 包括了比较常用的sed awk等命令
1 Linux主要shell命令详解 2 Linux bash shell脚本语法入门 3 Shell基本命令 4 使用 sed 编辑器
创建Shell脚本文件,编写如下过程:首先创建MAC地址的存储文件,然后使用arping命令,根据IP地址探测局域网中的主机获取对应的信息记录,应用grep命令、sed命令、awk命令对信息记录进行筛选,最后将筛选后的信息通过...
15Shell编程之函数及脚本案例讲解 16Shell编程之函数及脚本案例讲解 17Linux下Shell编程FIND、SED命令实战 18Linux下Shell编程FIND、SED命令实战 19Shell编程之awk、sed演练 20Shell编程之awk、sed演练( 21Shell编程...
Shell脚本开发从0开始
第16章 shell脚本介绍 151 第17章 条件测试 154 第18章 控制流结构 160 第19章 shell函数 202 第20章 向脚本传递参数 224 第21章 创建屏幕输出 236 第22章 创建屏幕输入 252 第23章 调试脚本 274 第24章 shell嵌入...
linux shell sed 使用详解 整理的很好。很不错的资源。写脚本全靠这个了。
shell sed awk作为shell编程的很好入门级文档,我开始学习的时候就是这个文档,现在遇到新手我就会推荐这个文档。
linux shell命令sed的使用方法
学习shell时做的笔记,包含sed,awk,sort,uniq的使用
11.Shell编程之SED及GREP综合讲解.mp4 12.Shell编程四剑客及案例详解.mp4 13.Linux下自动化运维企业案例.mp4 14.Linux系统增量备份脚本.mp4 15.自动收集服务器硬件系统信息脚本.mp4 16.Shell编程之磁盘监控报警脚本_...
Linux shell 编程中常用的文本处理工具 sed 和 gawk 的入门到进阶知识体系总结整理
SED单行脚本快速参考(Unix 流编辑器) sed命令使用说明