Как сделать удалить новые строки между данными каждой записи, которые расположены между двумя шаблонами?

Можно использовать

cd -

или Вы могли использовать

cd $OLDPWD
5
23.06.2015, 00:35
5 ответов

Подумайте это то, что вы хотите, используя GNU sed

 sed -n '/^PATTERN_START/,/^PATTERN_END/{
         //!{H;/^Record/!{x;s/\n\([^\n]*\)$/ \1/;x}};
         /^PATTERN_START/{h};/^PATTERN_END/{x;p;x;p};d
         };p' file

Объяснение

sed -n #Non printing


'/^PATTERN_START/,/^PATTERN_END/{
#If the line falls between these two patterns execute the next block

  //!{
  #If the previous pattern matched from the line above is not on matched(so skip 
         the start and end lines), then execute next block

        H;
        #append the line to the hold buffer, so this appends all lines between 
       #`/^PATTERN_START/` and `/^PATTERN_END/` not including those.

        /^Record/!{
        #If the line does not begin with record then execute next block

            x;s/\n\([^\n]*\)$/ \1/;x
            #Swap current line with pattern buffer holding all our other lines 
            #up to now.Then remove the last newline. As this only executed when 
            #record is not matched it just removes the newline from the start 
            #of `data`.
            #The line is then put switched back into the hold buffer.

        }
        #End of not record block

    }; 
    #End of previous pattern match block

    /^PATTERN_START/{h};

    #If line begins with `PATTERN_START` then the hold buffer is overwritten 
    #with this line removing all the previous matched lines.

    /^PATTERN_END/{x;p;x;p}
    #If line begins with `PATTERN_END` the swap in our saved lines, print them,
    #then swap back in the PATTERN END line and print that as well.

    ;d
    #Delete all the lines within the range, as we print them explicitly in the 
    #Pattern end block above


         };p' file
         # Print everything that's not in the range print, and the name of the file
8
27.01.2020, 20:31

Другие способы с sed :

sed '/PATTERN_START/,/PATTERN_END/{   # in this range
//!{                                  # if not start or end of range
/^Record/{                            # if line matches Record
x                                     # exchange pattern and hold space
/^$/d                                 # if pattern space is empty, delete it
s/\n/ /g                              # replace newlines with spaces
}
/^Record/!{                           # if line doesn't match Record
H                                     # append it to hold space
d                                     # then delete it
}
}
/PATTERN_END/{                        # at end of range
x                                     # exchange pattern and hold space
s/\n/ /g                              # replace newlines with space
G                                     # append hold space to pattern space
x                                     # exchange again
s/.*//                                # empty pattern space
x                                     # exchange again > empty line in hold space
}
}' infile

или

sed '/PATTERN_START/,/PATTERN_END/{     # same as above
//!{                                    # same as above
: again
N                                       # pull the next line into pattern space
/\nRecord/!{                            # if pattern space doesn't match this
/\nPATTERN_END/!{                       # and doesn't match this either
s/\n/ /                                 # replace newline with space
b again                                 # go to : again
}
}
P                                       # print up to first newline
D                                       # then delete up to first newline
}
}' infile

В одной строке:

sed '/PATTERN_START/,/PATTERN_END/{//!{/^Record/{x;/^$/d;s/\n/ /g};/^Record/!{H;d}};/PATTERN_END/{x;s/\n/ /g;G;x;s/.*//;x}}' infile

и

sed '/PATTERN_START/,/PATTERN_END/{//!{: again;N;/\nRecord/!{/\nPATTERN_END/!{s/\n/ /;b again}};P;D}}' infile
3
27.01.2020, 20:31

Перл путь:

perl -lne 'if(/^PATTERN_START/){$i=1; %data=(); print; next};
           if(/^PATTERN_END/){
             $i=0;
             if(defined($r)){
               print "$_ @{$data{$_}}" for sort keys(%data)
             }         
           }
           if($i==1){
            if(/^(Record\s*\d+)/){$r=$1;}
            else{push @{$data{$r}},$_}
           }   
           else{print}' file

И то же самое, что и закомментированный скрипт:

#!/usr/bin/env perl

## Read the input file line by line (this is the same as the `-n` flag)
while (<>) {
    ## If this line matches the start pattern, set $i to 1, clear
    ## the %data hash, print the line and skip to the next one.
    if(/^PATTERN_START/){
        $i=1;
        %data=();
        print;
        next
    }
    ## If this line matches the end pattern, set $i to 0
    if(/^PATTERN_END/){
        $i=0;
        ## If we're at the end pattern, we may have saved some
        ## data. This is the case if $r is defined.
        if(defined($r)){
            ## Print the current line, then the saved data associated
            ## with each of the records of this section.
            print "$_ @{$data{$_}}\n" for sort keys(%data)
        }          
    }
    ## If $i is 1, if we're inside a START and END pattern.
    if($i==1){
        ## Remove trailing newlines. This is equivallent to `-l` with
        ## the difference that `-l` also adds a newline to each print()
        ## call. We will add them manually here. 
        chomp;
        ## If this line starts with Record, 0 or more spaces and one
        ## or more numbers, save that as $r. 
        if(/^(Record\s*\d+)/){$r=$1;}
        ## If this line does not start with the above pattern, add it
        ## to the data saved for the current record. 
        else{push @{$data{$r}},$_}
    }
    ## For all other lines, print them as is. 
    else{print}
}
2
27.01.2020, 20:31

Это лучшее, что я мог придумать:

sed -n '/^PATTERN_START/, /^PATTERN_END/{
            /^PATTERN_START/{x;s/^.*$//;x};
            /^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};
            /^PATTERN_END/{x;/^\n/{s/^\n//p;d};s/\n/ /gp;g;p};
            /^Record/!H
        };   
        /^PATTERN_START/, /^PATTERN_END/!p'

Объяснение

Полагаю, вы знакомы с идеей удерживаемого пространства и пространства шаблонов в sed . В этом решении мы будем выполнять множество манипуляций в пространстве шаблонов. Итак, во-первых, отключите автоматическую печать с помощью параметра -n и печатайте везде, где это необходимо.

Первая задача - соединить все строки, которые находятся между Record строками.

Рассмотрим следующий файл:

a
b
Record 1
c
d
Record 2
e
f
Record 3

После объединения строк мы хотим, чтобы он был

a
b
Record 1 c d
Record 2 e f
Record 3

Итак, вот план:

  1. Мы читаем строку, добавляем ее в удерживаемое пространство.
  2. Если строка начинается с Запись , это означает, что предыдущая запись закончилась и началась новая запись. Итак, мы распечатываем удерживаемое пространство, промываем его и снова начинаем с пункта 1.

Пункт 1 реализуется кодом / ^ Record /! H (5-я строка в команде). Это означает, что «если строка не начинается с Record , добавить новую строку в удерживаемое пространство и добавить эту строку в удерживаемое пространство».

Пункт 2 может быть реализован с помощью кода / ^ Record / {x; s / \ n / / gp;} , где x меняет местами удержание и пространства шаблонов , Команда s заменяет все \ n на , а флаг p печатает пространство шаблонов. Использование x также имеет то преимущество, что теперь пространство удержания содержит текущую строку Record , так что мы можем начать еще один цикл точек 1 и 2.

Но у этого есть проблема. В данном примере есть две строки a b перед первой строкой Record .Мы не хотим заменять \ n на в этих строках. Поскольку они не начинаются с Запись , согласно пункту 1, \ n добавляется для удержания пробела, а затем эти строки добавляются. Итак, если первый символ удерживаемого пространства - \ n , это означает, что Запись ранее не встречалась, и мы не должны заменять \ n на . Это делается с помощью команды

/^\n/{s/^\n//p;d}

Таким образом, вся команда становится

/^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};

Теперь вторая сложность заключается в том, что мы хотим соединить строки, даже если строка Record не заканчивается Record , но строкой PATTERN_END . Мы хотим сделать то же самое, что и в пункте 2, даже если строка начинается с PATTERN_END . Таким образом, команда становится

/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp}

. Но с этим есть проблема. Как и в случае со строками Record , строка PATTERN_END теперь заканчивается в удерживаемом пространстве. Но мы знаем, что соединения строк после строки PATTERN_END больше не будет. Итак, мы можем распечатать это. Итак, мы переносим строку PATTERN_END в пространство шаблонов с помощью g и печатаем ее с помощью p . Таким образом, последняя команда становится

/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp;g;p}

Следующая проблема связана со строками PATTERN_START . В приведенном выше объяснении мы предполагали, что вначале удерживаемое пространство пусто. Но после PATTERN_END в удерживаемом пространстве что-то есть. (Это просто строка PATTERN_END ).Когда мы начинаем новый цикл с PATTERN_START , мы хотим очистить удерживаемое пространство.

Итак, что мы делаем, когда мы встречаем PATTERN_START , меняем местами содержимое удержания и пространств шаблонов, очищаем пространство шаблонов и снова меняем местами. Это делает трюмное пространство чистым. Именно это и делает следующая команда:

/^PATTERN_START/{x;s/^.*$//;x}

Последний штрих состоит в том, что мы хотим выполнять всю эту возню только между строками PATTERN_START и PATTERN_END . Остальные мы их просто печатаем. Это делается с помощью команд

/^PATTERN_START/, /^PATTERN_END/{
    ----above commands go here----
};
/^PATTERN_START/, /^PATTERN_END/!p

Соберите все это вместе, и это даст последнюю команду:)

6
27.01.2020, 20:31

Я сделал три версии этого.


v1


sed     -e'/^PATTERN_START/!b'  -e:n -eN  \
        -e'/\nPATTERN_END$/!bn' -eh\;s/// \
        -e'x;s/\n[[:print:]]*$//;x'       \
        -e's/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'  \
        -e'G;P;D'       data

Он распечатывает весь файл после внесения изменений только в строки записи , которые находятся между PATTERN_ {START, END} .


v2


sed   -ne'/\n/P;:n'    \
       -e'/^PATTERN_[OS]/!D'   -eN     \
       -e'/\nPATTERN_END$/!bn' -es///  \
       -e'/^PATTERN_S/s/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'      \
       -eG\;D  ./data                 ###<gd data> haha

Этот печатает строки записи в любом из ШАБЛОН _ {(START | OTHER), END} , но применяет правки только к тем, которые встречаются между ШАБЛОН_ {НАЧАЛО, КОНЕЦ} .


v3


sed   -ne'/\n/P;:n'    \
       -e'/^PATTERN_START/!D'  -eN     \
       -e'/\nPATTERN_END$/!bn' -es///  \
       -e's/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'      \
       -eG\;D  ./data

И только этот редактирует и только печатает строки записи , которые встречаются между PATTERN_ {START, END} .

Далее следует вывод каждого из них после прохождения через него входной выборки. Выходные образцы представлены в обратном порядке, от самого короткого до самого длинного.


v3


Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data

v2


Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 2         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data

v1


Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
PATTERN_END
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Data
Blabla
Blabla
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 2         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
PATTERN_END
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Blabla
Blabla
0
27.01.2020, 20:31

Теги

Похожие вопросы