shell脚本练习题

这里主要收集一些shell脚本练习题,用于加强shell编程能力。

Q1

分析图片服务日志,把日志(每个图片访问次数*图片大小的总和)排行,也就是计算每个url的总访问大小
说明:本题生产环境应用:这个功能可以用于IDC网站流量带宽很高,然后通过分析服务器日志哪些元素占用流量过大,进而进行优化或裁剪该图片,压缩js等措施。
测试数据
59.33.26.105 – – [08/Dec/2010:15:43:56 +0800] “GET /static/images/photos/2.jpg HTTP/1.1” 200 11299
本题需要输出三个指标: 【被访问次数】 【访问次数*单个被访问文件大小】 【文件名(带URL)】
查看答案

Q2

计算出1+2+3+..+100的结果。可以使用多种方法解答。
查看答案

Q3

分析网站日志,找出在一分钟内打开网页超过60次的ip(排除图片,js和css等静态元素),并用iptables禁止其访问。加入crontab使脚本每分钟执行一次。
查看答案

Q4

teamlist.txt的内容为:

  1. Name,Team,First Test, Second Test, Third Test
  2. Tom,Red,5,17,22
  3. Joe,Green,3,14,22
  4. Maria,Blue,6,18,21
  5. Fred,Blue,2,15,23
  6. Carlos,Red,-1,15,24
  7. Phuong,Green,7,19,21
  8. Enrique,Green,3,16,20
  9. Nancy,Red,9,12,24

编写一个awk脚本用来计算每个人的平均成绩,每次测试的平均成绩和每组队的平均成绩。如果某次成绩为负数,则表示此人错过了测试,那计算平均成绩时排除此人再计算。
输出的结果如下表,在名字的列表中,名字是10个宽度且左对齐(提示printf中使用%-10s格式),而平均值是7个字符宽度,右边两个右对齐的小数。

  1. Name       Average
  2. —-       ——-
  3. Tom          14.67
  4. Joe          13.00
  5. Maria        15.00
  6. Fred         13.33
  7. Carlos       19.50
  8. Phuong       15.67
  9. Enrique      13.00
  10. Nancy        15.00
  11. ——————
  12. Average for Test 1 : 5
  13. Average for Test 2 : 15.75
  14. Average for Test 3 : 22.125
  15. ——————-
  16. Average for Red Team: 16
  17. Average for Blue Team: 14.1667
  18. Average for Green Team: 13.8889

查看答案

Q5

传入至少三个数字参数到脚本file,并计算出最大,最小,平均值。需要判断传入的数字是否足够,否则输出警告信息。平均值保留两位小数。
如执行./file 3 4 6 5,输出结果如下:
max number is:6
min number is:3
average is:4.50
查看答案

Q6

有一列数字如下:
第1次:1
第2次:2
第3次:3
第4次:5
第5次:8
第6次:13
第7次:21
第8次:34
第9次:55
第10次:89
第11次:144
写出100次的数是什么。
查看答案

Q7

文件内容如下:
123abc456
456def123
567abc789
789def567
要求输出:
456ABC123
123DEF456
789ABC567
567DEF789
查看答案

shell脚本练习题答案

Q1答案

  1. awk ‘{url[$7]++;size[$7]+=$10}END{for (a in url) {print size[a]/1024"K",url[a],a}}’ access.log

解析:
这里定义了两个数组url和size,数组url用来计算单个url被访问的次数,数组size则是统计单个url传输的总字节数。之后的for语句则是循环读取数组url的无素,即链接,然后相继打印出单个url传输总字节数,被访问次数及相应的链接。
数据分析出来后,我们可以使用sort命令进行排序。

Q2答案

方法1:for…do…done 的数值处理

  1. sum=0
  2. for ((i=1;i<=100;i++))
  3. do
  4. ((sum+=$i))
  5. done

方法2:for…do…done (固定回圈)

  1. sum=0
  2. for i in {1..100}
  3. do
  4. ((sum+=$i))
  5. done

方法3:while do done (不定回圈)

  1. sum=0
  2. i=1
  3. while [[ $i -le 100 ]]
  4. do
  5. ((sum+=i))
  6. ((i++))
  7. done

方法4:until do done (不定回圈)

  1. sum=0
  2. i=1
  3. until [[ $i -gt 100 ]]
  4. do
  5. ((sum+=i))
  6. ((i++))
  7. done

方法5:构建1+2+3..再利用bc计算

  1. seq 100 | tr "n" "+" | sed ‘s/+$/n/’ | bc

Q3答案

  1. now=`date +%H%M%S`
  2. ago=`date -d "1 minute ago" +%H%M%S`
  3. badip=`tail -n 10000 access.log | egrep -v ".(gif|jpg|jpeg|png|css|js)" | awk  ‘
  4. BEGIN{
  5. n=’"$now"’
  6. a=’"$ago"’
  7. FS="[ :]+"
  8. }
  9. {
  10. t=$5$6$7
  11. if (t>=a && t<=n) {
  12. num[$1]++
  13. }
  14. }
  15. END{
  16. for (ip in num){
  17. if (num[ip]>60){
  18. print ip
  19. }
  20. }
  21. }
  22. ‘`
  23. if [ ! -z "$badip" ];then
  24. for ip in $badip;
  25. do
  26. if test -z "`/sbin/iptables -nL | grep $ip`";then
  27. /sbin/iptables -I INPUT -s $ip -j DROP
  28. fi
  29. done
  30. fi

解析:
1、定义两个变量now和ago,分别为当前时间,一分钟前的时间,格式为%H%M%S。
2、获取日志最后的一万行(可以根据自己的访问量修改),使用egrep排除图片等文件。
3、在awk的BEGIN语句中调用第1步设置的两个变量。
4、使用变量t,a,n判断并获取一分钟内的日志,并使用数组num统计ip出现的次数。
5、在END语句中判断ip出现的次数是否超过60,如果超过则输出ip地址到变量badip。
6、for循环获取变量badip中的每个ip,并加入iptables规则禁止访问。

Q4答案

  1. awk -F, ‘BEGIN{
  2. printf "%-10s %sn","Name","Average"
  3. printf "%-10s %sn","—-","——-"
  4. }
  5. NR>1{
  6. sum=0
  7. n=0
  8. for (i=3;i<=5;i++){
  9. if ($i>0){
  10. n++
  11. sum=sum+$i
  12. testcount[i-2]++
  13. testtotal[i-2]+=$i
  14. teamcount[$2]++
  15. teamtotal[$2]+=$i
  16. }
  17. }
  18. printf "%-10s %7.2fn",$1,sum/n
  19. }
  20. END{
  21. print "——————"
  22. for (j=1;j<=3;j++){
  23. print "Average for Test "j" : "testtotal[j]/testcount[j]
  24. }
  25. print "——————-"
  26. for (t in teamcount){
  27. print "Average for "t" Team: "teamtotal[t]/teamcount[t]
  28. }
  29. }’  teamlist.txt

解析:
1、awk的BEGIN语句输出表的两个列名。
2、NR>1表示只处理从第二行开始的数据
3、sum=0,n=0,初始化三个测试总成绩和参加的次数。
4、定义一个for循环,循环处理三次测试数据。
5、判断成绩大于0才处理此次测试。
6、为计算每个人的平均成绩,用变量n记录测试次数,变量sum累积三次的成绩,接着下面用printf格式化输出每个人的平均成绩;为计算三个测试中每次的平均成绩,以i-2作为索引(即第i-2次测试),数组testcount记录某次测试参加的人数,数组testtotal记录某次测试的总成绩;为计算每个组的平均成绩,以第二列组名作为索引,数组teamcount记录某组参加测试的人数,数组teamtotal记录某组的总成绩。
7、在END语句中用两个for循环语句分别输出每次测试及每组测试的平均成绩。

Q5答案

方法一:利用awk命令计算

  1. if [ "$#" -lt 2 ];then
  2. echo "parameter must be at least 3."
  3. exit 1
  4. fi
  5. echo "$@" | awk ‘
  6. BEGIN{
  7. RS=" +"
  8. }
  9. {
  10. sum+=$0
  11. }
  12. NR==1 {
  13. max=$1;min=$1
  14. next
  15. }
  16. $1>max {
  17. max=$1
  18. }
  19. $1<min {
  20. min=$1
  21. }
  22. END{
  23. printf "max number is:%sn",max
  24. printf "min number is:%sn",min
  25. printf "average is:%.2fn",sum/NR
  26. }’

解析:
1、判断参数是否大于2个,否则退出脚本。
2、管道传入所有参数到awk,并设置awk的RS为空格。
3、sum+=$0,计算和。
4、NR==1 {}把第一个参数先赋值到max和min,防止所有数字为负数时计算错误。
5、$1>max{}判断数字是否比变量max目前的数大,如果是,则把$1赋值到max,这样变量就可以时刻保持最大值状态。
6、$1<min{}同上原理。
7、最大打印出最大,最小值,平均则是sum/NR。
方法2:使用while,shift等命令

  1. n=$#
  2. if [ "$n" -lt 2 ];then
  3. echo "parameter must be at least 3."
  4. exit 1
  5. fi
  6. max=$1
  7. min=$1
  8. sum=$1
  9. shift
  10. while [ $# -gt 0 ]
  11. do
  12. ((sum+=$1))
  13. [ $1 -gt $max ] && max=$1
  14. [ $1 -lt $min ] && min=$1
  15. shift
  16. done
  17. echo "max number is:"$max
  18. echo "min number is:"$min
  19. ave=`echo "scale=2;$sum / $n" | bc`
  20. echo "average is:"$ave

解析:
1、把参数个数赋值到变量n
2、判断参数个数
3、把第一个数字赋值到max,min,sum变量,并用shift命令使参数向左移,即之前的$2变为$1,且变量$#减1。
4、while结合shift命令依次读取各参数,并在里面判断最大最小值。
5、echo输出最大最小值,bc计算平均值,定义scale=2以保留两位小数。

Q6答案

  1. a[1]=1
  2. a[2]=2
  3. i=3
  4. while [ $i -le 100 ]
  5. do
  6. ((a[$i]=${a[$i-1]}+${a[$i-2]}))
  7. ((i++))
  8. done
  9. echo ${a[100]}

Q7答案

  1. sed  ‘s/([0-9]*)([a-z]*)([0-9]*)/3U2E1/’ file

解析:
1、([0-9]*)匹配连续的数字,([a-z]*)匹配连续的小写字母。
2、123表示引用之前的括号内容,U2E表示把2的字母转换为大写字母。

iptables学习笔记

数据包流向顺序

我们来讨论数据包是以什么顺序、如何穿越不同的链和表的。稍后,在你自己写规则时,就会知 道这个顺序是多么的重要。一些组件是iptables与内核共用的,比如,数据包路由的判断。了解到这一点是 很重要的,尤其在你用iptables改变数据包的路由时。这会帮助你弄明白数据包是如何以及为什么被那样路 由,一个好的例子是DNAT和SNAT,不要忘了TOS的作用。 继续阅读iptables学习笔记

awk学习笔记

一、使用awk

1、调用awk

awk [options] -f progfile [–] file …

awk [options] [–] ‘program’ file …

2、命令行选项

-F fs

–field-separator fs

设置字段分隔符,如打印用户:

awk -F : ‘{print $1}’ /etc/passwd

-f source-file

–file source-file

从文件读取程序,如:awk -f file /etc/passwd

file内容为:

#!/bin/awk -f

BEGIN {FS=”:”}

{print $1}

-v var=val

–assign var=val

设置var的值为val,如:awk -v foo=hello -v bar=world ‘BEGIN {print foo,bar}’

3、包含其它文件到awk程序

@include “test1”

BEGIN {

print “This is script test2.”

}

二、正则表达式

1、如何使用正则表达式

搜索含foo字符的行,并打印第二列:

awk ‘/foo/ { print $2 }’ BBS-list

-| 555-1234

-| 555-6699

-| 555-6480

-| 555-2127

也可以使用如下形式:

exp ~ /regexp/或exp !~/regexp/

打印第1列含J的行

awk ‘$1 ~ /J/’ inventory-shipped

Jan 13 25 15 115

Jun 31 42 75 492

Jul 24 34 67 436

Jan 21 36 64 620

2、转义字符

有些字符需要转义,如双引号”

awk ‘BEGIN { print “He said ”hi!” to her.” }’

下面是一些转义字符代表的意思:

\

代表

b

Backspace, Ctrl-h, ASCII code 8 (BS).

n

换行符

r

回车

t

TAB键

3、正则表达式操作符

抑制有特殊命令的字符,如$表示$本身。

^

表示字符开始

$

表示字符结束

.

表示单个字符

[…]

中括号表达式,匹配方括号号任一字符

[^ …]

反向匹配中括号内任一字符

|

或,如^P|M匹配P开头或M

(…)

对字符分组,里面可使用|,如@(samp|code){[^}]+}匹配@code{foo}和@samp{bar}

*

匹配之前字符的0个或更多

+

与*相比,只是匹配1个或更多

?

匹配前面字符的0个或1个

{i}

匹配前面字符的i个,i是整数

{i,j}

匹配前面字符的i至j个,包含i和j

{i,}

匹配前面字符的i个或i个以上

4、gawk特有的正则操作符

s

表示空格字符

S

非空格字符

w

匹配字母或数字或下划线或汉字等

W

匹配任意不是字母,数字,下划线,汉字的字符

/匹配stow而不匹配stowaway

y

5、大小写敏感

x = “aB”

if (x ~ /ab/) … # this test will fail

IGNORECASE = 1

if (x ~ /ab/) … # now it will succeed

IGNORECASE = 1可以使用在命令行中,也可以使用在BEGIN中

三、读取输入文件

awk读取文件是一行行读取,并默认以空格分割成一个个字段。

涉及读取文件的有几个变量:

FS:

字段分隔符,默认是空格

RS:

记录分隔符,默认是换行符

NF:

记录每行的字段数,变量。

NR:

记录数,变量。

1、打印linux所有用户名

awk ‘BEGIN {FS=”:” } {print $1}’ /etc/passwd

2、打印最后一列

awk ‘BEGIN {FS=”:” } {print $NF}’ /etc/passwd

3、纵向排列每个字段

awk ‘BEGIN {RS=”:”} {print}’ /etc/passwd

4、统计行数

awk ‘END {print NR}’ /etc/passwd

四、打印输出

1、print使用方法

语法:print item1, item2, …

示例:

awk ‘BEGIN { print “line onenline twonline three” }’

awk ‘{ print $1, $2 }’ inventory-shipped

2、输出分隔符

OFS:

输出字段分隔符

ORS:

输出记录分隔符

以百分号分隔字段,记录隔一空白行输出。

awk ‘BEGIN{FS=”:”;OFS=”%”;ORS=”nn”} {print $1,$2}’ /etc/passwd

3、printf用法

语法:printf format, item1, item2, …

格式符号:

%c

转换数字成ASCII,如printf “%c”, 65结果为A。

%d, %i

打印十进制整数,如printf “%dn”, 6.5’结果为6.。

%e, %E

转换数字为科学(指数)符号,如printf “%4.3en”, 1950结果为1.950e+03。

%f

以浮点表示法打印数字,如 printf “%4.3f”, 1950结果为1950.000

%s

打印字符串,如printf “%10sn”, 1950,结果为十个空格加1950。

可更改的格式:

N$

位置指示符,可调整字符串的输出位置。printf “%s %s %sn”, “linux”, “like”,”I”输出为:linux like I,我们调整一下位置,printf “%3$s %2$s %1$sn”, “linux”, “like”,”I”,输出结果为:I like linux

负号,用在宽度前面,用来设置左对齐,因为默认是右对齐,如printf “%-4s”, “foo”,输出则是向左对齐了。

空格

待解

+

待解

示例:

1)第1列10个宽度并向左对齐:

$ awk ‘{ printf “%-10s %sn”, $1, $2 }’ BBS-list

-| aardvark 555-5553

-| alpo-net 555-3412

-| barfly 555-7685

-| bites 555-1675

-| camelot 555-0542

-| core 555-2912

-| fooey 555-1234

-| foot 555-6699

-| macfoo 555-6480

-| sdace 555-3430

-| sabafoo 555-2127

4、print和printf输出重定向

print items > output-file

保存items到文件,如分别保存用户和家目录,awk -F: ‘{ print $1 > “username”;print $6 > “home” }’ /etc/passwd

print items | command

管道重定向items到命令,如统计用户数量,awk -F: ‘{ print $1 |”wc -l” }’ /etc/passwd

五、表达式

1、操作符

算术操作符

– x

负运算

+ x

正运算,转换成数字。

x ^ y

x ** y

指数运算。

x * y

相乘。

x / y

相除,结果为浮点数字,如3 / 4 为:0.75

x + y

相加

x – y

相减

赋值

lvalue += increment Adds increment to the value of lvalue.

lvalue -= decrement Subtracts decrement from the value of lvalue.

lvalue *= coefficient Multiplies the value of lvalue by coefficient.

lvalue /= divisor Divides the value of lvalue by divisor.

lvalue %= modulus Sets lvalue to its remainder by modulus.

lvalue ^= power

lvalue **= power Raises lvalue to the power power. (c.e.)

递增和递减操作

++lvalue

Increment lvalue, returning the new value as the value of the expression.

lvalue++

Increment lvalue, returning the old value of lvalue as the value of the expression.

–lvalue

Decrement lvalue, returning the new value as the value of the expression. (This expression is like ‘++lvalue’, but instead of adding, it subtracts.)

lvalue–

Decrement lvalue, returning the old value of lvalue as the value of the expression. (This expression is like ‘lvalue++’, but instead of adding, it subtracts.)

2、真值与条件

在awk中,任何非0数值或非空字符串值为真,其它的值(0或空字符串)为假。

BEGIN {

if (3.1415927)

print “A strange truth value”

if (“Four Score And Seven Years Ago”)

print “A strange truth value”

if (j = 57)

print “A strange truth value”

}

变量类型与比较表达式

$ echo ‘ +3.14’ | gawk ‘{ print $0 == ” +3.14″ }’ True

-| 1

$ echo ‘ +3.14’ | gawk ‘{ print $0 == “+3.14” }’ False

-| 0

$ echo ‘ +3.14’ | gawk ‘{ print $0 == “3.14” }’ False

-| 0

$ echo ‘ +3.14’ | gawk ‘{ print $0 == 3.14 }’ True

-| 1

$ echo ‘ +3.14’ | gawk ‘{ print $1 == ” +3.14″ }’ False

-| 0

$ echo ‘ +3.14’ | gawk ‘{ print $1 == “+3.14” }’ True

-| 1

$ echo ‘ +3.14’ | gawk ‘{ print $1 == “3.14” }’ False

-| 0

$ echo ‘ +3.14’ | gawk ‘{ print $1 == 3.14 }’ True

-| 1

比较运算符

Expression Result

x < y True if x is less than y.

x y True if x is greater than y.

x >= y True if x is greater than or equal to y.

x == y True if x is equal to y.

x != y True if x is not equal to y.

x ~ y True if the string x matches the regexp denoted by y.

x !~ y True if the string x does not match the regexp denoted by y.

subscript in array True if the array array has an element with the subscript subscript.

布尔表达式

boolean1 && boolean2

boolean1 和boolean2 两个为真时,整个表达式才为真。

boolean1 || boolean2

至少一个为真,此表达式为真。

! boolean

boolean为真时,此表达式为假。

条件表达式

selector ? if-true-exp : if-false-exp

x >= 0 ? x : -x

x>=0时,x的值不变,x<=0时,x=-x。

3、函数调用

awk ‘{ print “The square root of”, $1, “is”, sqrt($1) }’

4、操作优先级

下面的操作符,由高到低排列:

(…)

分组

$

字段引用

++ —

递增,增减

^ **

取幂

+ – !

加,减,逻辑非

* / %

乘,除,取余

+ –

加,减

字符连接

没有特殊的符号,仅仅根据并排写。

< >= >> | |&

~ !~

匹配,不匹配

in

数组成员

&&

逻辑与

||

逻辑或

?:

条件。

= += -= *= /= %= ^= **=

赋值。

六、模式,动作,变量

1、模式元素

/regular expression/

/foo|bar|baz/ { buzzwords++ }

expression

$ awk ‘$1 == “foo” { print $2 }’ BBS-list

$ awk ‘$1 ~ /foo/ { print $2 }’ BBS-list

$ awk ‘/2400/ && /foo/’ BBS-list

$ awk ‘/2400/ || /foo/’ BBS-list

pat1, pat2

awk ‘$1 == “on”, $1 == “off”‘ myfile

BEGIN

END

$ awk ‘

> BEGIN { print “Analysis of ”foo”” }

> /foo/ { ++n }

> END { print “”foo” appears”, n, “times.” }’ BBS-list

-| Analysis of “foo”

-| “foo” appears 4 times.

BEGINFILE

ENDFILE

Special patterns for you to supply startup or cleanup actions to done on a per file basis. (See BEGINFILE/ENDFILE.)

empty

匹配所有输入。

2、在程序中使用shell变量

printf “Enter search pattern: ”

read pattern

awk -v pat=”$pattern” ‘$0 ~ pat { nmatches++ }

END { print nmatches, “found” }’ /path/to/data

3、动作

[pattern] { action }

pattern [{ action }]

function name(args) { … }

一个动作可以由一个语句或多个语句组合,包含在大括号里。各语句可以由新行或者分号分隔。默认的动作是打印记录。

Awk支持如下语句:

表达式:

调用函数或给变量赋值。

控制语句:

if, for, while,do

复合语句:

if, while, do的组合。

输入语句:

Getline

输出语句:

Print和printf

删除语句:

删除数组。

4、控制语句 in Actions

If-else语句:

if (condition) then-body [else else-body]

if (x % 2 == 0)

print “x is even”

else

print “x is odd”

While语句:

while (condition)

Body

awk ‘{

i = 1

while (i <= 3) {

print $i

i++

}

}' inventory-shipped

Do-while语句:

do

body

while (condition)

{

i = 1

do {

print $0

i++

} while (i <= 10)

}

For语句:
for (initialization; condition; increment)

Body

awk ‘{

for (i = 1; i <= 3; i++)

print $i

}' inventory-shipped

Switch语句:

switch (expression) {

case value or regular expression:

case-body

default:

default-body

}

switch (NR * 2 + 1) {

case 3:

case “11”:

print NR – 1

break

case /2[[:digit:]]+/:

print NR

default:

print NR + 1

case -1:

print NR * -1

}

Break语句:

# find smallest divisor of num

{

num = $1

for (div = 2; div * div num) {

printf “%d is primen”, num

break

}

}

}

Continue语句:

只在for语句里面使用。

BEGIN {

for (x = 0; x <= 20; x++) {

if (x == 5)

continue

printf "%d ", x

}

print ""

}

Next语句:

强制awk立即停止处理当前记录,而处理下一条记录。

NF != 4 {

err = sprintf(“%s:%d: skipped: NF != 4n”, FILENAME, FNR)

print err > “/dev/stderr”

next

}

Exit语句:

exit [return code]

BEGIN {

if ((“date” | getline date_now) “/dev/stderr”

exit 1

}

print “current date is”, date_now

close(“date”)

}

5、内置变量

用来控制awk的内置变量:

FS

字段分隔符,默认是空格

IGNORECASE

IGNORECASE为非0或者非空,则大小写不敏感。

OFS

输出字段分隔符。

ORS

输出记录分隔符。

RS

记录分隔符。

传递信息的内置变量:

FNR

当前文件记录数,当一个新文件读入时,清空此变量。

NF

字段数量

NR

记录数,新文件读入时不清空。

七、函数

http://www.gnu.org/software/gawk/manual/gawk.html#Functions

官方文档:http://www.gnu.org/software/gawk/manual/gawk.html

sed学习笔记

一、sed的行选择

打印第三行(3表示等号,p表示打印)

  1. sed -n ‘3p’ /etc/passwd

打印2至5行

  1. sed -n ‘2,5p’ /etc/passwd

从第2行开始,每隔2行打印一行

  1. sed -n ‘2~3p’ /etc/passwd

打印最后一行

  1. sed -n ‘$p’ /etc/passwd

打印包含或不包含root的行

  1. sed -n ‘/root/p’ /etc/passwd
  2. sed -n ‘/root/! p’ /etc/passwd

打印包含/bin/bash的行(%regexp%可以不用转义斜杠)

  1. sed -n ‘%/bin/bash%p’ /etc/passwd

忽略大小写的搜索

  1. sed -n ‘%/BIN/bash%Ip’ /etc/passwd或sed -n ‘//BIN/bash/Ip’ /etc/passwd

搜索从开始到sshd字符的范围

  1. sed -n ‘0,/sshd/p’ /etc/passwd

二、sed的正则表达式语法

char
只匹配本身char
*
匹配之前字符的0个或更多
+
与*相比,只是匹配1个或更多
?
匹配前面字符的0个或1个
{i}
匹配前面字符的i个,i是整数
{i,j}
匹配前面字符的i至j个,包含i和j
{i,}
匹配前面字符的i个或i个以上
(regexp)
分组字符,两个作用1、(abcd)*会搜索0个或多个abcd字符,abcd是作为一个整体2、作为反向引用,可以使用1 2等引用。
.
匹配任何字符,包括换行符
^
匹配行的开始
$
匹配行的结束
[list]
匹配list中的任单字符,如l,i,s,t
[^list]
反向匹配l,i,s,t
regexp1|regexp2
匹配regexp1或者regexp2
regexp1regexp2
匹配regexp1与regexp2连接
n
匹配换行字符
char
匹配特殊字符,如$, *, ., [, , ,^

三、常用命令

在之前sed的行选择我们使用了p,即打印命令,下面介绍更多的命令
q
退出命令,sed ’11 q’ /etc/passwd 相当于head /etc/passwd
d
删除命令,sed ‘1 d’ /etc/passwd 删除第一行
p
打印命令,一般与-n选项连用

四、替换命令s

s是sed中最常用到且最重要的命令了,下面详细介绍此命令的用法。
sed最简单的用法如下:
把root替换成rooter
sed ‘s/root/rooter/’ /etc/passwd

命令的格式为:s/regexp/replacement/flags

replacement可以是n(n为1到9的数字),表示引用regexp里的(matching):如
echo “123abc” | sed ‘s/([0-9]*).*/1/’
([0-9]*).*匹配了123abc,而([0-9]*)匹配123,所以1内容为123,所以这个例子的结果为123。

replacement也可以是&,表示reqexp匹配到的内容,如:
echo “123 abc” | sed ‘s/[0-9]*/& &/’
结果为:
123 123 abc

replacement还可以是L, l, U, u, E,意思如下:
L
把replacement字母转换成小写,直到U或E出现。
l
把下个字符转换成小写。
U
把replacement字母转换成大写,直到L或E出现。
u
把下个字符转换成大写。
E
停止以L或U开始的大小写转换。
一些例子如下:

  1. 1、把ABC转换为小写
  2. echo "ABC" | sed ‘s/[A-Z]*/L&E/’ 或
  3. echo "ABC" | sed ‘s/[A-Z]/l&/g’
  4. 把abc转换为大写
  5. echo "abc" | sed ‘s/[a-z]*/U&E/’ 或
  6. echo "abc" | sed ‘s/[a-z]/u&/g’

flags的可选值如下:
g
将replacement应用于所有reqexp所匹配的,不仅仅是第一个的匹配。
number
只替换第n个的匹配
p
当替换已经完成,打印新的结果
w file-name
当替换完成,把新结果保存到文件
I
i
忽略大小写。
M
m
使^和$为空字符

五、少用的命令

y/source-chars/dest-chars/
source-chars与dest-chars长度要相同,转换是一一对应的,如a转换成A,b转换成B:sed ‘y/ab/AB/’

a
text
在指定位置增加内容,如在含有root下一行增加I am root:
sed ‘/root/ aI am root’ /etc/passwd

i
text
在指定位置插入内容,如在含有root上一行增加I am root:
sed ‘/root/ iI am root’ /etc/passwd

c
text
用text替换匹配的行,如把含有root的行内容替换为I am root:
sed ‘/root/ cI am root’ /etc/passwd
=
打印行号,如显示含有root所在的行号:sed -n ‘/root/=’ /etc/passwd

l n
以n个长度分割匹配到的行,并以结尾,如以长度为4个字符分隔含有root的行:sed ‘/root/ l 4’ /etc/passwd

r filename
读取文件到输出,如在含有root的行下面插入file文件:sed ‘/root/r file’ /etc/passwd

w filename
保存输出流到文件,如保存含有root的行到file文件:sed ‘/root/w file’ /etc/passwd

N
增加一行并附下一行内容,如两行合并成一行:sed ‘N;s/n//’ /etc/passwd

六、一些示例

文本间隔:
——–
# 在每一行后面增加一空行

  1. sed G /etc/passwd

# 将原来的所有空行删除并在每一行后面增加一空行。
# 这样在输出的文本中每一行后面将有且只有一空行。

  1. sed ‘/^$/d;G’

# 在每一行后面增加两行空行

  1. sed ‘G;G’

# 在匹配式样“regex”的行之后插入一空行

  1. sed ‘/regex/G’

编号:
——–
# 为文件中的每一行进行编号(简单的左对齐方式)。这里使用了“制表符”
# (tab,见本文末尾关于’t’的用法的描述)而不是空格来对齐边缘。

  1. sed = /etc/passwd | sed ‘N;s/n/t/’

# 对文件中的所有行编号,但只显示非空白行的行号。

  1. sed ‘/./=’ filename | sed ‘/./N; s/n/ /’

# 计算行数 (模拟 “wc -l”)

  1. sed -n ‘$=’

选择性地显示特定行:
——–
# 显示文件中的前10行 (模拟“head”的行为)

  1. sed 10q /etc/passwd

# 显示文件中的第一行 (模拟“head -1”命令)

  1. sed q

# 只显示匹配正则表达式的行(模拟“grep”)

  1. sed -n ‘/regexp/p’               # 方法1
  2.  sed ‘/regexp/!d’                 # 方法2

# 显示包含“AAA”、“BBB”或“CCC”的行(任意次序)

  1. sed ‘/AAA/!d; /BBB/!d; /CCC/!d’  # 字串的次序不影响结果

# 显示包含65个或以上字符的行

  1. sed -n ‘/^.{65}/p’

# 显示包含65个以下字符的行

  1. sed -n ‘/^.{65}/!p’            # 方法1,与上面的脚本相对应
  2.  sed ‘/^.{65}/d’                # 方法2,更简便一点的方法

# 从第3行开始,每7行显示一次

  1. sed -n ‘3~7p’                   # 只对GNU sed有效
  2.  sed -n ‘3,${p;n;n;n;n;n;n;}’     # 其他sed

示例摘自:http://sed.sourceforge.net/sed1line_zh-CN.html
官方文档:http://www.gnu.org/software/sed/manual/sed.html