Combine dois greps em um único comando

1

Eu tenho alguns XML parecidos com isto:

    <artifactId>myproject</artifactId>
    <version>1.14.0-SNAPSHOT</version>

Eu quero extrair a versão, ou seja, 1.14.0-SNAPSHOT . Eu sei como fazer isso usando dois greps e um pipe:

$ grep -A1 "<artifactId>myproject</artifactId>" pom.xml | grep -Eo "\d+.\d+.\d+-SNAPSHOT"

Como posso combinar os dois em um? Eu estaria melhor usando o awk ou o sed para essa tarefa?

    
por David Kennedy 15.08.2016 / 22:08

2 respostas

2

Se tiver certeza de <version> na próxima linha depois de myproject

sed -n '
    \|<artifactId>myproject</artifactId>|{
        n                                           #get next line
        s|[[:blank:]]*</\?version>[[:blank:]]*||gp  #remove tags and print
    }
' pom.xml

Ou se você tiver pgrep

grep -zoP '<artifactId>myproject</artifactId>\s*\n\s*<version>\K[^<]+' pom.xml
    
por 15.08.2016 / 22:13
2

Você mencionou nos comentários que deseja algo portátil. Isso é admirável, mas eu realmente exorto você a não fazer isso de qualquer maneira. XML é uma linguagem contextual e regex não é. Não há como uma expressão regular analisar o XML corretamente como resultado.

Na melhor das hipóteses, você recebe um hack, que só é válido desde que o XML permaneça no mesmo formato. Mas como a especificação XML diz que o formato pode acaso e reter a mesma semântica, isso é uma suposição perigosa e cria um código frágil.

Eu sei que você tem motivos para querer fazer isso - você já tem uma resposta que lhe dá um jeito de fazer isso. Eu sugeriria que um analisador ainda é a resposta correta .

Mas com analisadores XML, você obtém xpath - que é muito parecido com expressões regulares, mas é aplicável a informações hierárquicas.

Algo parecido com isto:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> parse ( \*DATA );

my $version = $twig -> get_xpath('//item/artifactId[string()="myproject"]/../version',0)->text;
print $version;

__DATA__
<xml>
  <item>
    <artifactId>myproject</artifactId>
    <version>1.14.0-SNAPSHOT</version>
  </item>
</xml>

Espero que você possa ver como o xpath está funcionando? //item encontra um item em qualquer lugar dentro da estrutura. [string()= consulta o conteúdo do texto. Você poderia fazer algo como [@someAtt="fish"] para verificar um atributo.

Então, .. up (para item ) e obtemos o elemento version . Em seguida, obtenha o valor text .

Como um oneliner:

perl -MXML::Twig -0777 -e 'print XML::Twig -> parse ( <> ) -> get_xpath('/item/artifactId[string()="myproject"]/../version',0)->text,"\n"    yourxmlfile.xml

Agora, estou sugerindo XML::Twig porque acho mais fácil aprender. XML::LibXML também é muito bom.

Mas ele é distribuído com o strawberry perl no Windows e está disponível em muitos gerenciadores de pacotes - ou em CPAN .

Alternativamente - xmlstarlet deve permitir que você faça praticamente a mesma coisa.

    
por 30.08.2016 / 12:05