4

我正在尝试拆分文件。sed可用于执行此操作,例如

sed -e '0,/expr/d' filename

将在“expr”之后给出文件的下半部分但是如果出现不止一次并且我想在第 n 次出现后拆分怎么办?我想在第二次出现之后我是否想要它

sed -e '0,/expr/! {/expr/,$d}' filename

给出文件的上半部分直到 "expr" 的第二个匹配项。感叹号 (!) 告诉它忽略第一个范围,仅将大括号中的命令应用于文件的其他部分。

但是更一般的情况呢?例如,从倒数第二次开始。

我一直在sed这里使用,但我认为awk也会有优雅的解决方案。

4

3 回答 3

2

简单的awk解决方案:

  1. 直到并包括第$nth 场比赛/regex/

    awk -vn=$n '{print}/regex/&&!--n{exit}'

  2. 最多但不包括第$nth 场比赛:

    awk -vn=$n '/regex/&&!--n{exit}{print}'

    在上述两个程序中,将 n 设置为 0 将打印整个文件。此外,两种用法{print}都可以更改为,1;因为默认操作是{print}. (或者只是1在第二个程序中。)

    为了完整性:

  3. $n比赛结束后的一切:

    awk -vn=$n 'n<=0;/regex/{--n}'

注意:正如@mklement0 在评论中指出的那样,在 BSD Awk 版本(又名“one-true-awk”,据我所知仍然由 Brian 维护的版本)中,命令行选项解析中存在一个错误Kernighan) 2010 年 5 月 23 日之前;这显然包括随 Mac OS X 分发的版本(从 v10.9 开始)。因此,如果您使用这些 awk 版本之一,则需要编写-v n=$n而不是-vn=$n.

于 2013-11-06T02:43:23.923 回答
2

awk除了@rici的解决方案之外,还有一些变体

  1. 直到并包括第$nth 场比赛:

    awk -v n=$n 'p<n; /regex/{p++}' file

  2. 最多但不包括第$nth 场比赛:

    awk -v n=$n '/regex/{p++} p<n' file

  3. 来自并包括$n比赛

    awk -v n=$n '/regex/{p++} p>=n' file

  4. 来自且不包括$n匹配项

    awk -v n=$n 'p>=n; /regex/{p++}' file


但是更一般的情况呢?例如,从倒数第二次开始。

在这种情况下,简单的方法是使用 反向读取文件tac,执行上述选项并反向再次打印。

  1. 从并包括$n最后一场比赛

    tac file | awk -v n=$n 'p<n; /regex/{p++}' | tac

  2. 从但不包括$n最后一场比赛

    tac file | awk -v n=$n '/regex/{p++} p<n' | tac

  3. 直到$n最后一场比赛

    tac file | awk -v n=$n '/regex/{p++} p>=n' | tac

  4. 直到并且不包括$n最后一场比赛

    tac file | awk -v n=$n 'p>=n; /regex/{p++}' | tac


@mklement0在评论中指出的 OS X 用户注意事项

  • 可怜的 [stock] OS X 用户(从 OS X 10.9 开始)不走运:没有tac

  • 在 OS X 上你可以使用tail -r(注意tail在 Linux 上似乎不支持-r)。

于 2013-11-06T04:12:54.243 回答
0

这可能对您有用(GNU sed):

sed -nr 'x;/^X{2}/{x;p;b};x;/REGEXP/{x;s/^/X/;x}' file

这将在第二场比赛之后打印出任何内容REGEXP

注意REGEXP每行可能出现一次或多次,但只会计算一次。

于 2013-11-06T09:15:54.220 回答