删除匹配和上一行 [英] Remove matching and previous line

查看:185
本文介绍了删除匹配和上一行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用grep,awk,sed或其他东西从流中删除包含不是动态可执行文件和上一行的行。我目前的工作解决方案是将整个流去掉换行符,然后用sed替换其他的换行符,然后使用tr来添加换行符,然后使用grep -v。我对这种方法有些厌倦,但我现在还没有看到我能做的事情:

  tr'\\\
''|'| sed's / | \不是动态可执行文件/ __ MY_REMOVE / g'| tr'|''\\\
'

编辑:



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

大多数简单地用 pcregrep 在多行模式下:

  pcregrep -vM'\\\
\tnot一个动态可执行文件'filename

如果 pcregrep 是不可用,那么 awk sed 也可以通过读取一行并跳过先前的打印当出现一个标记行时。



使用awk你可能会感到无聊(并且明智):

  awk'/ ^ \不是动态可执行文件/ {flag = 1;下一个}!标志&& NR> 1 {print lastline; } {flag = 0; lastline = $ 0} END {if(!flag)print}'filename 

即:

  / ^ \不是一个动态可执行文件/ {#以行标记开始的行
flag = 1#设置一个标志
next#并且什么都不做(不要打印最后一行)
}
!flag&& NR> 1 {#如果最后一行没有被标记,
#不是第一行
print lastline#打印它
}
{#如果你有这么多,
flag = 0#取消设置标志
lastline = $ 0#并记住该行可能是
#。
}
END {#最后
if(!flag)print#打印最后一行,如果没有标记
}

但是sed很有趣:

  sed' :一个; $! {N; / \不要一个动态的可执行文件/ d; P:小号/.* \\\
//; ba}'filename

解释:

 :a#跳转标签

$! {#除非我们达到了输入的结尾:

N#获取下一行,并附加

/ \\\不属于动态可执行文件/ d#if结果包含一个换行符
#,后面跟着\不是一个动态可执行文件,放弃
#模式空间,并从下一行开始在
#开头。这实际上是
#从输出中删除匹配行和
#之前的行。

#否则:
P#将模式空间打印到换行符
s /.* \\\
//#删除刚从
#模式空间,所以只有
#第二行在它

ba#并且转到
}
#并且最后在这里放下打印
#最后一行(除非它被丢弃)。

或者,如果文件足够小以便完全存储在内存中:

  sed':a $!{N; ba}; s / [^ \\\
] * \ n \不是动态可执行文件[^ \\\
] * \ n // g'文件名

其中

 :a $!{N; ba}#将整个文件读入
#模式空间
s / [^ \\\
] * \ n \不是动态可执行文件[^ \\\
] * \ n // g #并剪掉违规位。


I need to remove a line containing "not a dynamic executable" and a previous line from a stream using grep, awk, sed or something other. My current working solution would be to tr the entire stream to strip off newlines then replace the newline preceding my match with something else using sed then use tr to add the newlines back in and then use grep -v. I'm somewhat weary of artifacts with this approach, but I don't see how else I can to it at the moment:

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

EDIT:

Input is a list of mixed files piped to xargs ldd, basically I want to ignore all output about non library files since that has nothing to do with what I'm doing next. I didn't want to use lib*.so mask since that could concievably be different

解决方案

Most simply with pcregrep in multi-line mode:

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

If pcregrep is not available to you, then awk or sed can also do this by reading one line ahead and skipping the printing of previous lines when a marker line appears.

You could be boring (and sensible) with awk:

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

That is:

/^\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
}

But sed is fun:

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

Explanation:

: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).

Or, if the file is small enough to be completely stored in memory:

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

Where

: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.

这篇关于删除匹配和上一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆