使用sed处理多行数据

1:32:00 PM 0 Comments

使用sed处理多行数据


数据文件txt: 一列,N行. 现在要把前m行摊开,剩下的依次跟上,另外保证精度不变。

比如8行:
0.15
0.28
0.36
0.42
5.12
43.5
234.1
3.14
变成
0.15 0.28 0.36 0.42
5.12 43.5 234.1 3.14

现在,我使用 sed来实现这个功能,当然,题目有点不清楚,不知是只处理前m行,还是每m行处理一次,前者似乎正是题目描述的,虽然后者更像真的。不过,我们都实现一下。我的解决方案似乎不是很精巧,不过确实有效。

首先科普两个sed概念:

  • hold space: 是一个保留空间,在一次 sed 处理里面,这个东东是唯一的,感觉有点像 static 变量,呵呵
  • pattern space: 是当前处理的空间,正常的讲,就是当前处理的行,不过,因为有了hold space,加上一些处理命令,就可以把多个行一起处理了

有了这两个概念,下面讲着就不费劲了。

只处理前m行

以 t 为你的测试数据文件,如果你只想以第m行为分隔输出的话,假设m为4

~$ sed -ne 'H;1h;4{x;s/\n/\ /gp};5h;${x;s/\n/\ /gp}' t
0.15 0.28 0.36 0.42
5.12 43.5 234.1 3.14

这个处理的思路是,每次都把当前行放到 hold space 中去,到了第m行或最后一行,一起取出来打印,中间有一点小波折,就显得比较长,是这样的:

  • H -- 这条命令对所有行生效,功能是对 hold space 附加一个回车,然后把
    pattern space 中的内容,也就是当前行附加进 hold space;
  • 1h -- 这条命令对第一行有效,把第一行的 pattern space,也就是第一行的内容直接覆盖进 hold space,对第一行来说,与 H 相比,仅仅是去掉了一个回车,因为后面我们要替换回车为空格,这个多余的回车就显得有一点讨厌了,呵呵。
  • 4{x;s/\n/\ /gp} -- 这个仅对第四行生效,也就是第 m 行,当前的 pattern space就是当前行,而当前的 hold space 已经执行过又一次 H 了,所以内容应该是
    line#1
    line#2
    ...
    line#m
    现在做如下处理:
    x -- 交换 pattern space 和 hold space,这样,上述内容就在 pattern space 里面了,这时就可以进行替换了
    s/\n/\ /gp -- 把 pattern space 中所有(g=globle) \n(\n=newline) 替换(s=
    substitute) 为空格(\ ),并打印(p=print)。如此就完成了前m行的输出。
  • 5h -- 把第5行,也就是 m+1 行写入 hold space,经过第m行的上述交换,hold space里面是第 m 行的内容,现在写入第 m+1 行,就清除了里面的前一行的内容。
  • ${x;s/\n/\ /gp} -- 在最后一行 ($) 进入的时候收拾残局,处理和第m行是一样的。

此外,关于 sed 的选项开关, -n 是没有明确指示(p)不输出,-e 就是执行后面的匹配操作

继续测试,假设m为3

~$ sed -ne 'H;1h;3{x;s/\n/\ /gp};4h;${x;s/\n/\ /gp}' t
0.15 0.28 0.36
0.42 5.12 43.5 234.1 3.14

看来m不是4也可以 :)

每隔m行处理一次

如果你想以m的倍数分隔,假设m为4

~$ sed -ne 'H;1h;4~4{x;s/\n/\ /gp};5~4h;${x;s/\n/\ /gp}' t
0.15 0.28 0.36 0.42
5.12 43.5 234.1 3.14

这里仅有两处需要追加解释的:

  • 4~4,也就是 m~m,是处理从 m 开始,间距为 m 的所有行,也就是 n*m
  • 5~4,是 m+1~m,是处理从 m+1 开始,间距为 m 的所有行,也就是 n*m +1

下面测试,假设m为3

~$ sed -ne 'H;1h;3~3{x;s/\n/\ /gp};4~3h;${x;s/\n/\ /gp}' t
0.15 0.28 0.36
0.42 5.12 43.5
234.1 3.14

证明 N/m 有余数也是可以的

假设m为2

~$ sed -ne 'H;1h;2~2{x;s/\n/\ /gp};3~2h;${x;s/\n/\ /gp}' t
0.15 0.28
0.36 0.42
5.12 43.5
234.1 3.14

证明 N 是 m 的大于2的整数倍 (N/m=4) 也是可以的。

大家可以考虑优化一下处理 :P

从文件中提取代理服务器信息

原始数据中包含若干 nn.nnn.nn.nnn:pp@HTTP 这样的信息,当然,一行可能有多个,也可能只有一个,现在要提取出来其中的代理信息,变成每行一个, nn.nnn.nn.nnn:pp的形式。

首先

sed -e 's/\@HTTP/\n/g'

确保每行一个,然后

sed -n -e 's/.*[^0-9]\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)
\.\([0-9]*\):\([0-9]*\)[[:space:]]*$/\1\.\2\.\3\.\4:\5/gp'

提取地址,并输出。

Some say he’s half man half fish, others say he’s more of a seventy/thirty split. Either way he’s a fishy bastard.