Ambos awk
e sed
são geralmente inadequados para analisar XML (e outros formatos semelhantes, como JSON e YAML, etc.). Para este exemplo de XML, por exemplo, não sabemos qual ordem os nós em InvoiceLines
estão armazenados ou se eles são delimitados por novas linhas ou não. O formato XML não se preocupa com essas coisas, mas um script awk
ou sed
cairia facilmente a menos que cuidados excepcionais fossem tomados para cobrir todos os casos possíveis (incluindo as várias codificações possíveis dos dados), caso em que você faria Teria que escrever um analisador XML de qualquer maneira.
Portanto, usar um analisador de XML, como o construído em xmlstarlet
, é a coisa certa a se fazer.
O comando a seguir deve imprimir o nome do arquivo de entrada se pelo menos um dos nós requeridos for encontrado no arquivo file.xml
. Se vários InvoiceLines
nós correspondessem, o nome do arquivo seria impresso várias vezes com uma nova linha no meio. Isso significa que, desde o início, desqualificamos nomes de arquivos contendo novas linhas.
xmlstarlet sel \
-t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
--inp-name -nl file.xml
A consulta XPATH corresponderia a todos os InvoiceLines
que tinham subnós chargeType
e charge
com os valores especificados. Usar o @charge
em vez do charge
teria sido testado contra um atributo charge
no nó InvoiceLines
, a propósito.
Aplicando isso em todos os arquivos XML em um único diretório:
xmlstarlet sel \
-t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
--inp-name -nl ./*.xml
Se houver muitos arquivos e os itens acima gerarem um erro, você poderá usar xargs
:
printf '%s\n' ./*.xml | xargs xmlstarlet -t -m ...
Ou find
(também será pesquisado subdiretórios):
find . -type f -name '*.xml' -exec xmlstarlet -t -m ... {} +
canalize o resultado até uniq
se quiser tornar a listagem de arquivos única.
Eu usei o seguinte XML para testar o acima:
<BillingData>
<InvoiceLinesList>
<InvoiceLines>
<chargeType>D</chargeType>
<charge>99</charge>
</InvoiceLines>
<InvoiceLines>
<chargeType>D</chargeType>
<charge>99</charge>
</InvoiceLines>
<InvoiceLines>
<chargeType>E</chargeType>
<charge>99</charge>
</InvoiceLines>
</InvoiceLinesList>
</BillingData>