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

inotify-tools使用方法介绍

inotify-tools 是为linux下inotify文件监控工具提供的一套c的开发接口库函数,同时还提供了一系列的命令行工具,这些工具可以用来监控文件系统的事件。 inotify-tools是用c编写的,除了要求内核支持inotify外,不依赖于其他。inotify-tools提供两种工具,一是inotifywait,它是用来监控文件或目录的变化,二是inotifywatch,它是用来统计文件系统访问的次数。现在介绍一下它的使用方法。

安装方法

  1. wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
  2. tar xzf inotify-tools-3.14.tar.gz ;cd inotify-tools-3.14
  3. ./configure –prefix=/usr && make && su -c ‘make install’

使用例子

inotifywait

1、实时监控/home的所有事件(包括文件的访问,写入,修改,删除等)

  1. inotifywait -rm /home

2、监控/var/log/messeges中有关httpd的日志

  1. #!/bin/sh
  2.        while inotifywait -e modify /var/log/messages; do
  3.          if tail -n1 /var/log/messages | grep httpd; then
  4.            kdialog –msgbox "Apache needs love!"
  5.          fi
  6.        done

inotifywatch

1、统计/home文件系统的事件

  1. inotifywatch -v -e access -e modify -t 60 -r /home

参数说明

inotifywait

语法:
inotifywait [-hcmrq] [-e ] [-t ] [–format ] [–timefmt ] [ … ]
参数:
-h,–help
输出帮助信息
@
排除不需要监视的文件,可以是相对路径,也可以是绝对路径。
–fromfile
从文件读取需要监视的文件或排除的文件,一个文件一行,排除的文件以@开头。
-m, –monitor
接收到一个事情而不退出,无限期地执行。默认的行为是接收到一个事情后立即退出。
-d, –daemon
跟–monitor一样,除了是在后台运行,需要指定–outfile把事情输出到一个文件。也意味着使用了–syslog。
-o, –outfile
输出事情到一个文件而不是标准输出。
-s, –syslog
输出错误信息到系统日志
-r, –recursive
监视一个目录下的所有子目录。
-q, –quiet
指定一次,不会输出详细信息,指定二次,除了致命错误,不会输出任何信息。
–exclude
正则匹配需要排除的文件,大小写敏感。
–excludei
正则匹配需要排除的文件,忽略大小写。
-t , –timeout
设置超时时间,如果为0,则无限期地执行下去。
-e , –event
指定监视的事件。
-c, –csv
输出csv格式。
–timefmt
指定时间格式,用于–format选项中的%T格式。
–format
指定输出格式。
%w 表示发生事件的目录
%f 表示发生事件的文件
%e 表示发生的事件
%Xe 事件以“X”分隔
%T 使用由–timefmt定义的时间格式

inotifywatch

语法:
inotifywatch [-hvzrqf] [-e ] [-t ] [-a ] [-d ] [ … ]
参数:
-h, –help
输出帮助信息
-v, –verbose
输出详细信息
@
排除不需要监视的文件,可以是相对路径,也可以是绝对路径。
–fromfile
从文件读取需要监视的文件或排除的文件,一个文件一行,排除的文件以@开头。
-z, –zero
输出表格的行和列,即使元素为空
–exclude
正则匹配需要排除的文件,大小写敏感。
–excludei
正则匹配需要排除的文件,忽略大小写。
-r, –recursive
监视一个目录下的所有子目录。
-t , –timeout
设置超时时间
-e , –event
只监听指定的事件。
-a , –ascending
以指定事件升序排列。
-d , –descending
以指定事件降序排列。

可监听事件

access 文件读取
modify 文件更改。
attrib 文件属性更改,如权限,时间戳等。
close_write 以可写模式打开的文件被关闭,不代表此文件一定已经写入数据。
close_nowrite 以只读模式打开的文件被关闭。
close 文件被关闭,不管它是如何打开的。
open 文件打开。
moved_to 一个文件或目录移动到监听的目录,即使是在同一目录内移动,此事件也触发。
moved_from 一个文件或目录移出监听的目录,即使是在同一目录内移动,此事件也触发。
move 包括moved_to和 moved_from
move_self 文件或目录被移除,之后不再监听此文件或目录。
create 文件或目录创建
delete 文件或目录删除
delete_self 文件或目录移除,之后不再监听此文件或目录
unmount 文件系统取消挂载,之后不再监听此文件系统。

简单介绍RPM包制作方法

RPM是RedHat Package Manager(RedHat软件包管理工具)的缩写,是一种用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中。它生成具有.RPM扩展名的文件。使用rpm安装软件和管理软件非常的方便。而这节我们不是介绍如何使用rpm安装或管理软件,而是如何把源码制作成rpm包。
下面我们以制作nginx的rpm开始介绍其制作方法。以下操作在centos-5 32系统进行。

制作nginx的rpm例子

1、建立目录结构

/usr/src/redhat/SOURCES — 存放源代码,补丁,图标等文件。
/usr/src/redhat/SPECS — 存放用于管理rpm制作进程的spec文件。
/usr/src/redhat/BUILD — 解压后的文件存放在这里。
/usr/src/redhat/RPMS — 存放由rpmbuild制作好的二进制包。
/usr/src/redhat/SRPMS —存放由rpmbuild制作好的源码包。

  1. mkdir -p /usr/src/redhat
  2. cd /usr/src/redhat
  3. mkdir SOURCES SPECS BUILD RPMS SRPMS

2、下载源码包

下载源码包到SOURCES目录,不需要解压。

  1. cd /usr/src/redhat/SOURCES
  2. wget http://nginx.org/download/nginx-1.2.1.tar.gz

3、创建Spec文件

  1. cd /usr/src/redhat/SPECS
  2. vi nginx.spec

内容如下:

  1. #
  2. # Example spec file for nginx
  3. #
  4. Summary: high performance web server
  5. Name: nginx
  6. Version: 1.2.1
  7. Release: 1.el5.ngx
  8. License: 2-clause BSD-like license
  9. Group: Applications/Server
  10. Source: http://nginx.org/download/nginx-1.2.1.tar.gz
  11. URL: http://nginx.org/
  12. Distribution: Linux
  13. Packager: zhumaohai <[email protected]>
  14.  
  15. %description
  16. nginx [engine x] is a HTTP and reverse proxy server, as well as
  17. a mail proxy server
  18. %prep
  19. rm -rf $RPM_BUILD_DIR/nginx-1.2.1
  20. zcat $RPM_SOURCE_DIR/nginx-1.2.1.tar.gz | tar -xvf –
  21. %build
  22. cd nginx-1.2.1
  23. ./configure –prefix=/usr/local/nginx
  24. make
  25. %install
  26. cd nginx-1.2.1
  27. make install
  28. %preun
  29. if [ -z "`ps aux | grep nginx | grep -v grep`" ];then
  30. killall nginx >/dev/null
  31. exit 0
  32. fi
  33. %files
  34. /usr/local/nginx

4、开始RPM制作

在制作RPM包之前需要安装必要的工具,如rpmbuild,gcc等。

  1. yum install gcc rpm-build pcre-devel
  1. cd /usr/src/redhat/SPECS/
  2. rpmbuild -bb nginx.spec

一切顺利的话,会生成nginx的rpm包,/usr/src/redhat/RPMS/i386/nginx-1.2.1-1.el5.ngx.i386.rpm。

5、测试rpm包

  1. rpm -ivh /usr/src/redhat/RPMS/i386/nginx-1.2.1-1.el5.ngx.i386.rpm

spec文件解释

从以上的简单例子可以看出,制作rpm包最重要的还是spec文件,下面解释一下例子所用到的指令。
#:以#开头是注释,rpm会忽略它。
Summary:简单描述软件。
Name :定义rpm的名称。
Version: 定义软件版本
Release: 发行版本
License: 定义许可证
Group: 软件分类
Source: 源码下载地址
URL: 源码相关网站
Distribution: 发行版系列
Packager: 打包人的信息

%description:软件详细描述,可多行
%prep :软件编译之前的处理,如解压。
%build :开始编译软件,如make
%install :开始安装软件,如make install
%files :指定哪些文件需要被打包,如/usr/local/nginx
%preun :定义卸载之前的动作,如杀掉进程。
这里只介绍了几个常用的tag,更详细的请参考:http://www.rpm.org/max-rpm/ch-rpm-inside.html

DSN: Service unavailable

自从换了vps,博客的评论邮件提醒功能一直有问题,今天有空,我们来解决它。
无法发送邮件的日志如下:

  1. Jun 26 07:24:23 MyVPS1976 sendmail[31760]: q5PNOMeP031760: from=<www@MyVPS1976>, size=1393, class=0, nrcpts=1, msgid=<[email protected]>, proto=SMTP, daemon=MTA, relay=MyVPS [127.0.0.1]
  2. Jun 26 07:24:25 MyVPS1976 sendmail[31762]: q5PNOMeP031760: to=<[email protected]>, ctladdr=<www@MyVPS1976> (501/501), delay=00:00:02, xdelay=00:00:02, mailer=esmtp, pri=121393, relay=mxdomain.qq.com. [64.71.138.90], dsn=5.0.0,stat=Service unavailable
  3. Jun 26 07:24:25 MyVPS1976 sendmail[31762]: q5PNOMeP031760: q5PNOPeP031762: DSN: Service unavailable
  4. Jun 26 07:24:25 MyVPS1976 sendmail[31762]: q5PNOPeP031762: to=root, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=32578, dsn=2.0.0, stat=Sent

根据relay=mxdomain.qq.com. [64.71.138.90], dsn=5.0.0,stat=Service unavailable这一段,我们知道邮件已经发送出去,但由于某种原因邮件被拒绝,于是更换hostname,重启sendmail,解决问题。
更换hostname方法:
1、编辑/etc/sysconfig/network,更换文件中的hostnmae。
2、把hostname写入/etc/hosts
3、执行hostname devops.webres.wang立即生效

nginx 全局变量

经常需要配置Nginx ,其中有许多以 $ 开头的变量,经常需要查阅nginx 所支持的变量。
可能是对 Ngixn资源不熟悉,干脆就直接读源码,分析出支持的变量。
Nginx支持的http变量实现在 ngx_http_variables.c 的 ngx_http_core_variables存储实现:
Nginx
Nginx
Nginx
已Excel形式提供,方便查询:
http://files.cnblogs.com/AloneSword/nginx%E5%86%85%E7%BD%AE%E5%8F%98%E9%87%8F.rar
转自:http://www.cnblogs.com/AloneSword/archive/2011/12/10/2283483.html

rpmbuild在centos 5与centos 6用法的异同

之前是在centos 5上对软件进行rpm打包,今天需要在centos 6上打包,发现File not found: /root/rpmbuild/BUILDROOT/…的错误,看是centos 6中的rpmbuild topdir已经改变,为了能兼容centos 5的spec文件,需要对topdir进行修改:
打开/usr/lib/rpm/macros文件:

  1. %_topdir                %{getenv:HOME}/rpmbuild

更改为:

  1. %_topdir                %{_usrsrc}/redhat

另外还需要定义buildroot
在spec文件中的make install后面加上DESTDIR=%{buildroot},即:

  1. make install DESTDIR=%{buildroot}

DESTDIR是Makefile文件中定义的一个安装路径的变量,根据实际情况修改,比如mysql和nginx的是DESTDIR,而php的是INSTALL_ROOT。

修改xen vps系统时间

今天把博客vps搬到其它机房,连上新xen vps,修改时间,却怎么也不生效,特记录修改方法:

  1. cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  2. echo "xen.independent_wallclock=1" >>/etc/sysctl.conf
  3. /sbin/sysctl -p
  4. echo "/sbin/ntpdate  cn.pool.ntp.org" >>/etc/rc.local
  5. ntpdate cn.pool.ntp.org