Удалить совпадение и предыдущую строку

Мне нужно удалить строку, содержащую «не динамический исполняемый файл», и предыдущую строку из потока с помощью grep, awk, sed или чего-то другого. Моим текущим рабочим решением было бы tr весь поток, чтобы удалить новые строки, затем заменить новую строку, предшествующую моему совпадению, чем-то другим, используя sed, затем использовать tr, чтобы добавить новые строки обратно, а затем использовать grep -v. Я несколько устал от артефактов с этим подходом, но я не вижу, как еще я могу это сделать в данный момент:

tr '\n' '|' | sed 's/|\tnot a dynamic executable/__MY_REMOVE/g' | tr '|' '\n'

РЕДАКТИРОВАТЬ:

Ввод представляет собой список смешанных файлов, переданных в xargs ldd, в основном я хочу игнорировать все выходные данные о небиблиотечных файлах, поскольку это не имеет ничего общего с тем, что я делаю дальше. Я не хотел использовать маску lib*.so, так как это могло бы быть по-другому.


person Lev Kuznetsov    schedule 17.02.2015    source источник


Ответы (3)


Проще всего с pcregrep в многострочном режиме:

pcregrep -vM '\n\tnot a dynamic executable' filename

Если pcregrep вам недоступно, то awk или sed также могут это сделать, читая на одну строку вперед и пропуская печать предыдущих строк при появлении маркерной строки.

Вы можете быть скучным (и разумным) с awk:

awk '/^\tnot a dynamic executable/ { flag = 1; next } !flag && NR > 1 { print lastline; } { flag = 0; lastline = $0 } END { if(!flag) print }' filename

Это:

/^\tnot a dynamic executable/ {  # in lines that start with the marker
  flag = 1                       # set a flag
  next                           # and do nothing (do not print the last line)
}
!flag && NR > 1 {                # if the last line was not flagged and
                                 # is not the first line
  print lastline                 # print it
}
{                                # and if you got this far,
  flag = 0                       # unset the flag
  lastline = $0                  # and remember the line to be possibly
                                 # printed.
}
END {                            # in the end
  if(!flag) print                # print the last line if it was not flagged
}

Но sed весело:

sed ':a; $! { N; /\n\tnot a dynamic executable/ d; P; s/.*\n//; ba }' filename

Объяснение:

:a                                  # jump label

$! {                                # unless we reached the end of the input:

  N                                 # fetch the next line, append it

  /\n\tnot a dynamic executable/ d  # if the result contains a newline followed
                                    # by "\tnot a dynamic executable", discard
                                    # the pattern space and start at the top
                                    # with the next line. This effectively
                                    # removes the matching line and the one
                                    # before it from the output.

                                    # Otherwise:
  P                                 # print the pattern space up to the newline
  s/.*\n//                          # remove the stuff we just printed from
                                    # the pattern space, so that only the
                                    # second line is in it

  ba                                # and go to a
}
                                    # and at the end, drop off here to print
                                    # the last line (unless it was discarded).

Или, если файл достаточно мал, чтобы полностью храниться в памяти:

sed ':a $!{N;ba}; s/[^\n]*\n\tnot a dynamic executable[^\n]*\n//g' filename

Где

:a $!{ N; ba }                                  # read the whole file into
                                                # the pattern space
s/[^\n]*\n\tnot a dynamic executable[^\n]*\n//g # and cut out the offending bit.
person Wintermute    schedule 17.02.2015

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

sed 'N;/\n.*not a dynamic executable/d;P;D' file

Это сохраняет движущееся окно из 2 строк и удаляет их обе, если во второй найдена нужная строка. Если не первая строка печатается, а затем удаляется, а затем добавляется следующая строка, и процесс повторяется.

person potong    schedule 17.02.2015

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

Это предположение, учитывая, что вы не опубликовали какой-либо образец ввода и ожидаемый результат, но похоже, что все, что вам нужно, это (используя GNU awk для многосимвольного RS):

awk -v RS='^$' -v ORS= '{gsub(/[^\n]+\n\tnot a dynamic executable/,"")}1' file
person Ed Morton    schedule 17.02.2015