Удалите все строки между двумя шаблонами (исключая шаблон) с помощью sed или awk

У меня есть несколько большой выходной текстовый файл, где мне нужно удалить все строки между двумя шаблонами, но сохранить соответствие шаблону.

Файлы выглядят нечетко похожими на следующий вывод.

 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

Я написал следующий script (под 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?

Последнее замечание, мне нужно, чтобы этот script работал над относительно общей установкой Unix. Я должен отправить это кому-то, кто должен выполнить его по очень простой установке AIX (я думаю). Нет perl, нет python, и я не могу много разбираться в их установке по электронной почте.

Ответ 1

Попробуйте добавить точку с запятой после d, чтобы указать, что команда завершена. (GNU sed — только sed, который мне удобен для тестирования с помощью — не требует этого, но может быть, другой sed будет?)

Кроме того, если вам нужно поддерживать несколько реализаций sed, то вы не можете использовать + для обозначения "один или несколько": он не является стандартным, и не все его реализации поддерживают его. Вы можете использовать \{1,\}, но это довольно уродливо., Я бы просто использовал * и наложил дополнительную копию.

Итак:

sed '/^ * year/,/^ * _cons/{/^ * year/!{/^ * _cons/!d;}}' input.txt >output.txt

(Протестировано, но только с использованием GNU sed, а не OS X и, конечно же, не AIX, извините.)

Ответ 2

Это должно работать -

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

Это может сработать для вас:

 sed '/year/,/_cons/{//!d}' file

или

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

Ответ 4

Вы можете сделать это визуально. Просто откройте файл с помощью gVim и выполните команду:

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

Объяснение:

  • g глобальная команда
  • /^\s*year/+1 строка соответствия ниже year
  • /^\s*_cons/-1 строка соответствия выше _cons
  • d удалить диапазон

Ответ 5

Подводя итоги и обобщаем два решения GNU sed, которые работают:

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