- 论坛徽章:
- 23
|
感谢斑竹加精。
关于sed记数,补充2个例子,均来自info sed中的examples(略有改动)
例8:实现 awk '{print NR,$0}' 的功能- ly5066113@ubuntu:~$ head sed.info | awk '{print NR,$0}'
- 1 File: sed.info, Node: Top, Next: Introduction, Up: (dir)
- 2
- 3 sed, a stream editor
- 4 ********************
- 5
- 6 This file documents version 4.1.5 of GNU `sed', a stream editor.
- 7
- 8 Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004 Free Software
- 9 Foundation, Inc.
- 10
- ly5066113@ubuntu:~$ head sed.info | sed -nf test.sed
- 1 File: sed.info, Node: Top, Next: Introduction, Up: (dir)
- 2
- 3 sed, a stream editor
- 4 ********************
- 5
- 6 This file documents version 4.1.5 of GNU `sed', a stream editor.
- 7
- 8 Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004 Free Software
- 9 Foundation, Inc.
- 10
- ly5066113@ubuntu:~$ cat test.sed
- #! /usr/bin/sed -f
- x
- 1s/^/1/
- G
- s/\n/ /p
- s/ .*//
- /^9*$/s/^/0/
- s/.9*$/x&/
- h
- s/.*x//
- y/0123456789/1234567890/
- x
- s/x.*//
- G
- s/\n//
- h
复制代码 x #交换pattern space与hold space,保存读入的内容
1s/^/1/ #如果是第一行,初始化行号1
G #将保存的内容追加回pattern space
s/\n/ /p #将换行替换为空格,并打印
s/ .*// #去处空格以后的所有内容,pattern space只剩下行号
/^9*$/s/^/0/ #如果行号都为9,在前面补0
s/.9*$/x&/ #用x分隔不需要改变和需要改变的数字
h #将pattern space中的内容保存到hold space
s/.*x// #删除不需要改变的数字
y/0123456789/1234567890/ #对数字进行 +1 的操作
x #交换pattern space与hold space
s/x.*// #删除需要改变的数字
G #将改变后的数字追加回pattern space
s/\n// #删除换行,得到新的行号
h #保存新行号到hold space
整体的思路:
每读入一行记录,将保存在hold space中的行号(如果是第一行,需要初始化),和本行记录合并输出
然后将行号 +1 ,保存至hold space
代码的核心部分就是实现“行号 +1”,具体做法:
将行号分为2个部分,一部分保持不变(此部分可能没有),一部分进行改变,然后将需要改变的部分进行处理
将处理后的结果与前面不变的部分拼接在一起,形成新的行号,但这里有个情况需要考虑,就是进位
我们已实际的例子来看看
如果行号是 123
那么首先将其分成2个部分变为 12x3
x左边的12不需要改变,x右边的3需要变成4
那么就对3进行y/0123456789/1234567890/的操作,将其变成4
然后拼上前面的12变为 124
如果行号是129(需要进位)
那么首先将其分成2个部分变为 1x29
x左边的1不需要改变,x右边的29需要变成30
那么就对29进行y/0123456789/1234567890/的操作,将其变成30
然后拼上前面的1变为 130
这里面有个特殊情况需要考虑,就是如果行号都为9
9, 99, 999 之类的情况,那么我们需要在前面加数字0用做进位用
例9:实现 wc -c 的功能- ly5066113@ubuntu:~$ wc -c urfile
- 254 urfile
- ly5066113@ubuntu:~$ sed -nf test.sed urfile
- 254
- ly5066113@ubuntu:~$ cat test.sed
- #! /usr/bin/sed -f
- s/./a/g
- H
- x
- s/\n/a/
- : a; s/aaaaaaaaaa/b/g; t b; b done
- : b; s/bbbbbbbbbb/c/g; t c; b done
- : c; s/cccccccccc/d/g; t d; b done
- : d; s/dddddddddd/e/g; t e; b done
- : e; s/eeeeeeeeee/f/g; t f; b done
- : f; s/ffffffffff/g/g; t g; b done
- : g; s/gggggggggg/h/g; t h; b done
- : h; s/hhhhhhhhhh//g
- : done
- $! {
- h
- b
- }
- : loop
- /a/! s/[b-h]*/&0/
- s/aaaaaaaaa/9/
- s/aaaaaaaa/8/
- s/aaaaaaa/7/
- s/aaaaaa/6/
- s/aaaaa/5/
- s/aaaa/4/
- s/aaa/3/
- s/aa/2/
- s/a/1/
- y/bcdefgh/abcdefg/
- /[a-h]/ b loop
- p
复制代码 此段代码虽然看起来烦琐,但思路却比上一例好理解。
每读一行数据,将里面所有的字符都替换成字母a,因为sed读数据时会将换行符(\n)去掉
所以我们利用H命令产生的\n将其补充回来,也替换成字母a,统一做字符统计
为了节省内存开销,提高效率,这里做了进位的处理,就是将10个a替换成1个b,10个b替换成1个c 。。。
这样到最后,字母a的个数就代表个位数字,字母b的个数就代表十位数字,字母c的个数代表百位数字。。。
如果最后剩下是这样一串字符:
ccbbbbbaaaa
那么就表示总共的字符数为:254
本段代码的统计是有上限的,如果字符数量超过1亿,将无法得到正确结果
可以通过增加替换的次数来增加统计上限,如 s/hhhhhhhhhh/i/g , s/iiiiiiiiii/j/g 。。。 |
|