使用sed或awk删除两个模式之间的所有行(不包括模式本身)

10

我有一个相当大的输出文本文件,需要删除两个模式之间的所有行,但保留模式匹配。

文件大致看起来像以下输出。

 TEST #1          
      coef1 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
      coef2 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
            |
  indicator |
         0  |   .6647992   2.646627     0.25   0.802     -4.55925    5.888849
         1  |   2.118701   5.225777     0.41   0.686     -8.19621    12.43361
            |
       year |
         2  |  -.4324005   2.231387    -0.19   0.847    -4.836829    3.972028
         3  |   -.362762    1.97184    -0.18   0.854    -4.254882    3.529358
            |
      _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
 TEST #2          
        coef2 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
        coef3 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
              |
         year |
           4  |   .6647992   2.646627     0.25   0.802     -4.55925    5.888849
           5  |   2.118701   5.225777     0.41   0.686     -8.19621    12.43361
              |
     idnumber |
           6  |  -.4324005   2.231387    -0.19   0.847    -4.836829    3.972028
           7  |   -.362762    1.97184    -0.18   0.854    -4.254882    3.529358
              |
        _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
我需要取出以下输出,并删除所有在"year"和"_cons"之间的行,但我需要保留以"_cons"开头的行。期望的输出应该像这样:
 TEST #1          
      coef1 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
      coef2 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
            |
  indicator |
         0  |   .6647992   2.646627     0.25   0.802     -4.55925    5.888849
         1  |   2.118701   5.225777     0.41   0.686     -8.19621    12.43361
            |
       year |
      _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
 TEST #2          
        coef2 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
        coef3 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
              |
         year |
        _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
我写了下面这段脚本(在 OS X 系统下):
sed '/^ +year/,/^ +_cons/{/^ +year/!{/^ +_cons/!d}}' input.txt >output.txt

但是我遇到了以下错误:

sed: 1: "/^ +year/,/^ +_cons/{/^ ...": extra characters at the end of d command

我不确定这种方法是否正确,因为我似乎无法让sed执行。在这里使用sed是否合适,还是应该使用awk?

最后一点,我需要这个脚本在相对通用的Unix安装上工作。我必须将其发送给某人,在非常基本的AIX(我认为)安装下执行。没有perl、没有python,并且我不能通过电子邮件对他们的安装进行太多故障排除。

5个回答

6
这应该可以运行 -
awk '/year/{print; getline; while($0!~/_cons/) {getline}}1' INPUT_FILE

或者

awk '/_cons/{print;f=0;next}/year/{f=1;print;next}f{next}1' INPUT_FILE

以下是您输入的数据文件的输出结果:

[jaypal:~/Temp] awk '/year/{print; getline; while($0!~/_cons/) {getline}}1' file
TEST #1          
      coef1 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
      coef2 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
            |
  indicator |
         0  |   .6647992   2.646627     0.25   0.802     -4.55925    5.888849
         1  |   2.118701   5.225777     0.41   0.686     -8.19621    12.43361
            |
       year |
      _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
 TEST #2          
        coef2 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
        coef3 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
              |
         year |
        _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869

Test2:

[jaypal:~/Temp] awk '/_cons/{print;f=0;next}/year/{f=1;print;next}f{next}1' file
TEST #1          
      coef1 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
      coef2 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
            |
  indicator |
         0  |   .6647992   2.646627     0.25   0.802     -4.55925    5.888849
         1  |   2.118701   5.225777     0.41   0.686     -8.19621    12.43361
            |
       year |
      _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869
TEST #2          
      coef2 |   48.36895    3.32013    14.57   0.000     41.86141    54.87649
      coef3 |  -50.08894   10.47335    -4.78   0.000    -70.61697   -29.56092
            |
       year |
      _cons |   16.95753   6.342342     2.67   0.008     4.526383    29.38869

3
尝试在d后面添加分号,以表示命令已结束。(GNU sed - 我手头唯一可测试的sed - 不需要这样做,但另一个sed可能需要?) 此外,如果需要支持多个sed实现,则不能使用+表示“一个或多个”:它不是标准的,也不是所有实现都支持。您可以使用\{1,\},但那样太丑了...我只会使用*并附加一个额外的副本。
sed '/^ * year/,/^ * _cons/{/^ * year/!{/^ * _cons/!d;}}' input.txt >output.txt

(已测试,但只使用 GNU 的 sed,没有用过 OS X,更不用说 AIX 了,抱歉。)

这样做不会同时删除 year 行吗? - jaypal singh
@JaypalSingh:不是的...嗯,是的,但并没有什么深刻的原因:只是我没有将一个+实例替换为*。现在已经修复了。谢谢。 - ruakh

3
这可能对你有用:
 sed '/year/,/_cons/{//!d}' file

或者:

 awk '/_cons/{p=0};!p;/year/{p=1}' file

1

你可以通过可视化的方式来完成。 只需使用gVim打开文件,然后运行以下命令:

:g/^\s*year/+1,/^\s*_cons/-1 d

说明:

  • g 全局命令
  • /^\s*year/+1 匹配 year 下面的行
  • /^\s*_cons/-1 匹配 _cons 上面的行
  • d 删除范围内的内容

0

总结和归纳两个可行的GNU sed解决方案:

sed '/BEGIN/,/END/{/BEGIN/!{/END/!d;}}' input.txt
sed '/BEGIN/,/END/{//!d}' input.txt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接