AWK / SED在HUGE行之间提取字符串

时间:2016-01-20 20:06:50

标签: string awk sed line delimiter

我有一个很大的行是来自ws的回复,我需要获取<asunto></asunto>之间的所有字符串。该文件是这样的:

Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml";
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Body><ns1:consultarComunicacionesResponse xmlns:ns1="http://ve.tecno.afip.gov.ar/domain/service/ws"><ns2:RespuestaPaginada xmlns:ns2="http://ve.tecno.afip.gov.ar/domain/service/ws" xmlns:ns3="http://core.tecno.afip.gov.ar/model/ws/types" xmlns:ns4="http://ve.tecno.afip.gov.ar/domain/service/ws/types"><pagina>1</pagina><totalPaginas>1</totalPaginas><itemsPorPagina>100</itemsPorPagina><totalItems>2</totalItems><ns4:items><ns4:ComunicacionSimplificada><idComunicacion>sdfgsfdgsfdgsd</idComunicacion><cuitDestinatario>sdfgsdfgsdfgsfdg</cuitDestinatario><fechaPublicacion>sdfgsdfg</fechaPublicacion><fechaVencimiento>sdfgsdfgsdfg</fechaVencimiento><sistemaPublicador>sdfgsdfgsfg</sistemaPublicador><sistemaPublicadorDesc>sdfgsdfggf</sistemaPublicadorDesc><estado>2</estado><estadoDesc>sdfgsdfgsgf</estadoDesc><asunto>EXAMPLEEEEEEEEEEEEEEEE1</asunto><prioridad>3</prioridad><tieneAdjunto>sdfgfdg</tieneAdjunto></ns4:ComunicacionSimplificada><ns4:ComunicacionSimplificada><idComunicacion>sdfgsdfgdfg</idComunicacion><cuitDestinatario>sdfgdfsg</cuitDestinatario><fechaPublicacion>sdfgsdfg</fechaPublicacion><fechaVencimiento>sdfgdsfg</fechaVencimiento><sistemaPublicador>sdfgsdfg</sistemaPublicador><sistemaPublicadorDesc>sdfgsdfgdsfggsdf</sistemaPublicadorDesc><estado>1</estado><estadoDesc>dsfgsdfgsgd</estadoDesc><asunto>EXAMPLEEEEEEEEEEEEEEEE2</asunto><prioridad>asdfdsf</prioridad><tieneAdjunto>asdfasdf</tieneAdjunto></ns4:ComunicacionSimplificada></ns4:items></ns2:RespuestaPaginada></ns1:consultarComunicacionesResponse></soap:Body></soap:Envelope>    

我得到这样的东西:

EXAMPLEEEEEEEEEEEEEEEE1    
EXAMPLEEEEEEEEEEEEEEEE2

可能会有很多重复,介于0和数百之间。

谢谢!

6 个答案:

答案 0 :(得分:1)

您还可以使用 GNU grep

grep -oP '(?<=<asunto>)((?!</asunto>).)+(?=</asunto>)' yourfile

这利用了 Lookbehind 加上否定正面 Lookahead

Here's对其内部的一个很好的解释。

<强>性能

$ wc -l bigfile 
100000 bigfile

$ time awk -v RS='</?asunto>' '!(NR%2)' bigfile >/dev/null

real  0m0.277s
user  0m0.254s
sys 0m0.022s


$ time grep -oP '(?<=<asunto>)((?!</asunto>).)+(?=</asunto>)' bigfile >/dev/null

real  0m4.318s
user  0m4.292s
sys 0m0.020s

$ time awk -v RS='[<>]' '/\/asunto/{f=0;next} f; /asunto/{f=1}' bigfile >/dev/null

real  0m7.088s
user  0m6.928s
sys 0m0.021s
到目前为止,

@Ed 代码实现了最佳性能。

答案 1 :(得分:1)

使用GNU awk进行多字符RS:

$ awk -v RS='</?asunto>' '!(NR%2)' file
EXAMPLEEEEEEEEEEEEEEEE1
EXAMPLEEEEEEEEEEEEEEEE2

答案 2 :(得分:0)

awk救援!

$ awk -v RS='[<>]' '/\/asunto/{f=0;next} f; /asunto/{f=1}' file

EXAMPLEEEEEEEEEEEEEEEE1
EXAMPLEEEEEEEEEEEEEEEE2

更新:根据评论,如果标签存在于其他地方,您可以锚定在打开/关闭标签的左侧和右侧

$ awk -v RS='[<>]' '/^\/asunto$/{f=0;next} f; /^asunto$/{f=1}' file
EXAMPLEEEEEEEEEEEEEEEE1
EXAMPLEEEEEEEEEEEEEEEE2

或等效地检查确切的字符串匹配

$ awk -v RS='[<>]' '$0=="/asunto"{f=0;next} f; $0=="asunto"{f=1}' file
EXAMPLEEEEEEEEEEEEEEEE1
EXAMPLEEEEEEEEEEEEEEEE2

另请注意,并非所有awk变体都支持多字符RS。

答案 3 :(得分:0)

使用XML解析器(和awk删除标题)

awk -v RS= 'NR>1' ws.out | xmlstarlet sel  -t -v //asunto -n

答案 4 :(得分:0)

这可能适合你(GNU sed):

sed -nr '/<asunto>([^<]*)<\/asunto>/{s//\n\1\n/;s/[^\n]*\n//;P;D}' file

这会将字符串缩减为前置行,然后打印,删除此行并重复。不包含所需字符串的行将被忽略。

答案 5 :(得分:0)

正如其他地方所指出的,XML感知工具原则上会更安全,但如果没有“asunto”标记的嵌套,则以下GNU grep咒语可能会有用,即使{{{ 1}}和<asunto>为空或包含其他标记:

</asunto>

这里的关键是非贪婪的子表达式:grep -oP '(?<=<asunto>).*?(?=</asunto>)'