问题描述
我需要使用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.
这篇关于删除匹配和上一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!