sed用法学习[不定期更新]


用sed处理Apache日志文件

统计Apache日志单IP访问请求数排名。假设Apache日志内容access.log内容为:

10.0.0.41 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.43 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.42 - - [03/Dec/2010:23:27:01 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.46 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.42 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.41 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.41 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -
10.0.0.46 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 -

下面给出3种解决方案:

方法1:
[root@home /]# awk '{++S[$1]} END{for (home in S) print home ,S[home]}' access.log |sort -rn -k2

10.0.0.41 3
10.0.0.47 2
10.0.0.46 2
10.0.0.42 2
10.0.0.43 1
#提示:$1为第一个域的内容。sort中的 -k2 为对第二个字段排序,即对数量排序。

方法2:
[root@home /]# awk '{print $1}' access.log|sort|uniq -c |sort -rn -k1

3 10.0.0.41
2 10.0.0.47
2 10.0.0.46
2 10.0.0.42
1 10.0.0.43
提示:这个方法是容易想到的简单易用的方法。

方法3:
[root@home /]# sed 's/ - -.*$//g' access.log|sort|uniq -c|sort -rn -k1

3 10.0.0.41
2 10.0.0.47
2 10.0.0.46
2 10.0.0.42
1 10.0.0.43

提示:sed管道后的第一个sort是让所有一样的IP挨着,因为uniq -c只能对相邻的IP行去重计数。

uniq -c 显示唯一的行,并在每行行首加上出现的次数
sort -k1 -nr 按照第一个字段,进行数值排序,且为逆序
head -10 取前10行数据


注意:默认情况下sed并不会对文件的内容进行修改,只是把处理过后的内容输出,如果你要写回文件,你可以使用重定向,如:

$ sed "s/my/yours/g" pets.txt > yours_pets.txt #不能重定向到原文件!

使用 -i 参数直接修改文件内容

$ sed -i "s/my/yours/g" pets.txt
[小乐趣]用命令在终端上打印出乘法口诀表:
  • # seq 1 | awk '{for(i=1;i<10;i++){for(j=1;j<10;j++){printf "%d%s%d%s%dt",j,"+",i,"=",i+j;}printf "n"}}'
  • # seq 1 | awk '{for(i=1;i<10;i++){for(j=1;j<=i;j++){printf "%d%s%d%s%dt",j,"+",i,"=",i+j;}printf "n"}}'
  • # awk 'BEGIN{for(i=9;i>0;i--){for(j=9;j>=i;j--){printf "%d%s%d%s%dt",j,"-",i,"=",j-i;}printf "n"}}'
#!/bin/bash
for ((i=1;i<=9;i++))
do
	for ((j=1;j<=i;j++))
	do
		echo -n " $j*$i=$(($i*$j)) "
	done
echo
done
sed基本命令笔记

替换字符(含有/特殊符号的),这里命令中的斜杠/可以用其他符号代替,如用#号(如把/用@替换)

$ echo "http://ixyzero.com/" | sed 's#/#@#g'

如果一定要用/斜杠的话,命令必须把要替换的斜杠先转义

$ echo "http://ixyzero.com/" | sed 's///@/g'

匹配内容前/后增加某内容

在匹配forbag.cn内容后增加myfreelinux.com这一行内容
sed ‘/forbag.cn/amyfreelinux.com’ youfile
在匹配forbag.cn内容前增加myfreelinux.com这一行内容
sed ‘/forbag.cn/imyfreelinux.com’ youfile
$ sed ‘s#10#100#g’ example—–不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。

选定行的范围:逗号

$ sed -n '/test/,/check/p' example

所有在模板test和check所确定的范围内的行都被打印

$ sed -n '5,/^test/p' example

打印从第五行开始到第一个包含以test开始的行之间的所有行

$ sed '/test/,/check/s/$/sed test/' example

对于模板test和check之间的行,每行的末尾用字符串sed test替换

从文件读入:r命令
$ sed '/test/r file' example

file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面

[root@Jason64-17 sed]# cat sed-4.txt
1 2 3 4 5 6 7 8 9 10
[root@Jason64-17 sed]# cat sed-1.txt
i am lisp
i have a computer
it is very big
and i have no room
google is very nice
my friends usual alias nice for me
[root@Jason64-17 sed]# sed '/very/r sed-4.txt' sed-1.txt
i am lisp
i have a computer
it is very big
1 2 3 4 5 6 7 8 9 10
and i have no room
google is very nice
1 2 3 4 5 6 7 8 9 10
my friends usual alias nice for me
[root@Jason64-17 sed]# sed -n '/very/r sed-4.txt' sed-1.txt
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10

#删除带有script关键字的行

# sed '/script/d'

# 删除文件中的最后一行

# sed '$d'

# 打印/复制文档中两个正则表达式之间的内容(相当有用啊!)

# sed '/Iowa/,/Montana/p'

# 在每一行开头处插入5个空格(使全文向右移动5个字符的位置)

# sed 's/^/     /'
# 对文件中的所有行编号(行号在左,文字右端对齐)
# sed = filename | sed 'N; s/^/ /; s/ *(.{6,})n/1 /'
# 对文件中的所有行编号,但只显示非空白行的行号
# sed '/./=' filename | sed '/./N; s/n/ /'
选择性地删除特定行:
# 显示通篇文档,除了两个正则表达式之间的内容
sed '/Iowa/,/Montana/d'

# 删除文件中相邻的重复行(模拟 uniq 命令)
# 只保留重复行中的第一行,其他行删除
sed '$!N; /^(.*)n1$/!P; D'

# 删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存
# 大小,或者使用GNU sed。
sed -n 'G; s/n/&&/; /^([ -~]*n).*n1/d; s/n//; h; P'

# 删除除重复行外的所有行(模拟“uniq -d”)
sed '$!N; s/^(.*)n1$/1/; t; D'

# 删除文件中开头的10行
sed '1,10d'

# 删除文件中的最后一行
sed '$d'

# 删除文件中的最后两行
sed 'N;$!P;$!D;$d'

# 删除文件中的最后10行
sed -e :a -e '$d;N;2,10ba' -e 'P;D' # 方法1
sed -n -e :a -e '1,10!{P;N;D;};N;ba' # 方法2

# 删除8的倍数行
gsed '0~8d' # 只对GNU sed有效
sed 'n;n;n;n;n;n;n;d;' # 其他sed

# 删除匹配式样的行
sed '/pattern/d' # 删除含pattern的行。当然pattern
# 可以换成任何有效的正则表达式

# 删除文件中的所有空行(与“grep '.' ”效果相同)
sed '/^$/d' # 方法1
sed '/./!d' # 方法2

# 只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。
# (模拟“cat -s”)
sed '/./,/^$/!d' #方法1,删除文件顶部的空行,允许尾部保留一空行
sed '/^$/N;/n$/D' #方法2,允许顶部保留一空行,尾部不留空行

# 只保留多个相邻空行的前两行。
sed '/^$/N;/n$/N;//D'

# 删除文件顶部的所有空行
sed '/./,$!d'

# 删除文件尾部的所有空行
sed -e :a -e '/^n*$/{$d;N;ba' -e '}' # 对所有sed有效
sed -e :a -e '/^n*$/N;/n$/ba' # 同上,但只对 gsed 3.02.*有效

# 删除每个段落的最后一行
sed -n '/^$/{p;h;};/./{x;/./p;}'
编号:
--------

 # 为文件中的每一行进行编号(简单的左对齐方式)。这里使用了“制表符”
 # (tab,见本文末尾关于't'的用法的描述)而不是空格来对齐边缘。
 sed = filename | sed 'N;s/n/t/'

 # 对文件中的所有行编号(行号在左,文字右端对齐)。
 sed = filename | sed 'N; s/^/     /; s/ *(.{6,})n/1  /'

 # 对文件中的所有行编号,但只显示非空白行的行号。
 sed '/./=' filename | sed '/./N; s/n/ /'
# 只在行中出现字串“baz”的情况下将“foo”替换成“bar”
 sed '/baz/s/foo/bar/g'

 # 将“foo”替换成“bar”,并且只在行中未出现字串“baz”的情况下替换
 sed '/baz/!s/foo/bar/g'

 # 不管是“scarlet”“ruby”还是“puce”,一律换成“red”
 sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g'  #对多数的sed都有效
 gsed 's/scarlet|ruby|puce/red/g'               # 只对GNU sed有效
 # 只显示匹配正则表达式的行(模拟“grep”)
 sed -n '/regexp/p'               # 方法1
 sed '/regexp/!d'                 # 方法2

 # 只显示“不”匹配正则表达式的行(模拟“grep -v”)
 sed -n '/regexp/!p'              # 方法1,与前面的命令相对应
 sed '/regexp/d'                  # 方法2,类似的语法
sed的速度优化:当由于某种原因(比如输入文件较大、处理器或硬盘较慢等)需要提高
命令执行速度时,可以考虑在替换命令(“s/.../.../”)前面加上地址表达式来
提高速度。举例来说:

   sed 's/foo/bar/g' filename         # 标准替换命令
   sed '/foo/ s/foo/bar/g' filename   # 速度更快
   sed '/foo/ s//bar/g' filename      # 简写形式

当只需要显示文件的前面的部分或需要删除后面的内容时,可以在脚本中使用“q”
命令(退出命令)。在处理大的文件时,这会节省大量时间。因此:

   sed -n '45,50p' filename           # 显示第45到50行
   sed -n '51q;45,50p' filename       # 一样,但快得多

以上的大部分内容是从sed1line中文版中摘抄和学习然后自己进行了测试的,于此做个记录。

,

《“sed用法学习[不定期更新]”》 有 1 条评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注