删除匹配和上一行

时间:2015-02-17 16:50:00

标签: regex awk sed grep tr

我需要使用grep,awk,sed或其他东西从流中删除包含“非动态可执行文件”和前一行的行。我目前的工作解决方案是在整个流中删除新行,然后使用sed替换我匹配之前的换行符,然后使用tr添加新行,然后使用grep -v。用这种方法我有点厌倦了文物,但我现在还不知道我还能做些什么:

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

编辑:

输入是通过管道传输到xargs ldd的混合文件列表,基本上我想忽略所有关于非库文件的输出,因为这与我接下来要做的事情无关。我不想使用lib * .so掩码,因为它可以完全不同

3 个答案:

答案 0 :(得分:5)

最简单的是在多行模式中使用pcregrep

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

如果您无法使用pcregrep,则awksed也可以通过读取前一行并在标记线出现时跳过前一行的打印来执行此操作。 / p>

你可能对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.

答案 1 :(得分:1)

请记住,虽然grep和sed是面向行的,但awk是面向记录的,因此可以轻松处理跨越多行的问题。

如果您没有发布任何样本输入和预期输出,这是一个猜测,但听起来就像您需要的一样(使用GNU awk进行多字符RS):

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

答案 2 :(得分:1)

这可能适合你(GNU sed):

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

这将保持2行的移动窗口,如果在第二行中找到所需的字符串,则删除它们。如果不是,则打印第一行然后删除,然后附加下一行并重复该过程。