Incrementar arquivos xml com bash

0

Um bom amigo em um fórum ajudou-me a criar este roteiro, mas tudo o que eu lancei resultou errado e não sei por que ou qual é o problema. Eu corri todo o meu script no terminal do Ubuntu se questionado como bash test.sh.

Meu objetivo é incrementar várias tags process></process> do arquivo .xml, mas alguns arquivos podem ter de 1 a 100 tags.

Exemplo:

 - jfksaJDFH
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - jdhkjasdh
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>
 - <process>value=""</process>

Após o script:

 - jfksaJDFH
 - <process>value="1"</process>
 - <process>value="2"</process>
 - <process>value="3"</process>
 - <process>value="4"</process>
 - jdhkjasdh
 - <process>value="5"</process>
 - <process>value="6"</process>
 - <process>value="7"</process>
 - <process>value="8"</process>

Script:

#!/bin/bash

dir="/mnt/Desktop/test/"

while IFS= read -r -d '' file
do
    i=1
    while IFS= read -r -u 3 line
    do
        if [[ $line = '<process></process>' ]]; then
           echo "<process>value=\"$((i++))\"</process>"
        else
           echo "$line"
        fi
    done 3< "$file" > "$file.xml"
done < <(find $dir -type f -name \*.xml -print0)

quando o script acima é executado, remove o último <process>value=""</process>

modifique o script para isso:

while IFS= read -r -d '' file
do
    i=1
    while IFS= read -r -u 3 line
    do
        if [[ $line = '<process></process>' ]]; then
           echo "$line"
        else
           echo "<process>value=\"$((i++))\"</process>"
        fi
    done 3< "$file" > "$file.xml"
done < <(find $dir -type f -name \*.xml -print0)

A saída do arquivo é esta:

<process>value="1"</process>
<process>value="2"</process>
<process>value="3"</process>
<process>value="4"</process>
<process>value="5"</process>
<process>value="6"</process>
<process>value="7"</process>
<process>value="8"</process>
<process>value="9"</process>
<process>value="10"</process>
<process>value="11"</process>
<process>value="12"</process>
<process>value="13"</process>
<process>value="14"</process>
<process>value="15"</process>
<process>value="16"</process>
<process>value="17"</process>
<process>value="18"</process>
<process>value="19"</process>
<process>value="20"</process>
<process>value="21"</process>
<process>value="22"</process>
<process>value="23"</process>

que, em outras palavras, incrementa, mas remove todos os outros conteúdos da página.

    
por DᴀʀᴛʜVᴀᴅᴇʀ 07.12.2012 / 22:46

3 respostas

1

coloque este script em um arquivo (ex: 'increase.awk'):

BEGIN { i = 1 }
/.*<process>value=""<\/process>.*/ { split($0, a, "value=\"\"") ; print a[1] "value=\"" i++ "\"" a[2] ; next }
/.*/ { print $0 }

e depois ligue:

gawk -f increase.awk < yourinputfile

explicação: no awk, split("string", a, "separatorstring") divide a "string" em uma matriz chamada a, usando "separatorstring" como separador. Então, um [1] contém tudo até a primeira "separatorstring", então um [2] contém tudo até o final da linha ou até a próxima "separatorstring", etc.

    
por 08.12.2012 / 02:32
0

Você notou que reverteu a lógica do construto if-then-else quando você reescreveu o script

observe o posicionamento das linhas comentadas com line1 e line2 abaixo. Você os reverteu em seu código reescrito

while IFS= read -r -d '' file
do
    i=1
    while IFS= read -r -u 3 line
    do
        if [[ $line = '' ]]; then
           echo "value=\"$((i++))\""   # line 1 ***************
        else
           echo "$line"                # line 2 ***************
        fi
    done 3 "$file.xml"
done 

espero que isso ajude

    
por 07.12.2012 / 23:15
0

Por favor, não faça XML assim. Considere se você quiser - XML é um tipo de dados estruturado que ignora ativamente o espaço em branco. Tem tags unários, como <attr name="fish" /> e outras coisas que significam se você analisa linha por linha, usando expressões regulares um dia seu código irá misteriosamente quebrar.

A maneira de fazer isso é com um XML Parser. Qual deles você usa é uma questão de gosto, mas para scripts eu gosto de XML::Twig (módulo perl).

Para resolver seu problema conforme descrito:

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

sub increment_value {
    my ( $twig, $process ) = @_;
    my ($value) = ( $process->text =~ m/(\d+)/ );
    print "Got $value\n";
    if ( defined ( $value ) ) { 
        $process->set_text( 'value="' . ++$value . '"' );
    } 
    else {
        $process -> delete;
    }
}

my $twig = XML::Twig->new(
    'pretty_print'  => 'indented',
    'twig_handlers' => { 'process' => \&increment_value },
);
$twig->parsefile( 'your_file.xml'  );
$twig->print;    #prints to stdout.

Isso aciona um 'manipulador' para cada elemento process , que extrai, transforma e substitui o texto.

    
por 28.04.2015 / 16:25

Tags