[Gelöst] Suchen und ersetzen mit Hilfe mehrerer Parameter

J

Jacko

Grünschnabel
Hallo zusammen,

ich bin an einem Punkt angekommen, wo ich nicht mehr weiter komme und hoffe ihr könnt mir weiter helfen.
Anbei ein Ausschnitt aus einer xml Datei:

Code:
<Position>
        <SKU>A/370269/10432/32D</SKU>
        <Batch>00320160501</Batch>
        <Description>Carlotta</Description>
        <Amount>1</Amount>
        <ForeignPos1>172991</ForeignPos1>
        <ForeignPos2>10</ForeignPos2>
        <Positionreferences>
          <PosReference number="1"/>
          <PosReference number="2"/>
          <PosReference number="3">0</PosReference>
          <PosReference number="4">0</PosReference>
          <PosReference number="5"/>
          <PosReference number="6">370269</PosReference>
          <PosReference number="7">10432</PosReference>
          <PosReference number="8">pearl grey</PosReference>
          <PosReference number="9"/>
          <PosReference number="10"/>
          <PosReference number="11">26 INCH</PosReference>
        </Positionreferences>
</Position>
<Position>
        <SKU>A/370269/10432/32D</SKU>
        <Batch>00520160501</Batch>
        <Description>Carlotta</Description>
        <Amount>6</Amount>
        <ForeignPos1>172992</ForeignPos1>
        <ForeignPos2>10</ForeignPos2>
        <Positionreferences>
          <PosReference number="1"/>
          <PosReference number="2"/>
          <PosReference number="3">0</PosReference>
          <PosReference number="4">0</PosReference>
          <PosReference number="5"/>
          <PosReference number="6">370269</PosReference>
          <PosReference number="7">10432</PosReference>
          <PosReference number="8">pearl grey</PosReference>
          <PosReference number="9"/>
          <PosReference number="10"/>
          <PosReference number="11">26 INCH</PosReference>
        </Positionreferences>
</Position>

Im Moment nutze ich ein Skript, dass mir die beiden Zeilen mit den Referenzen 9 & 10 mit Hilfe von einem übergebenem Parameter verändert. Aufruf erfolgt mit z.B.
Code:
vtqichange test.xml 4711/0815

Code:
#!/bin/bash

if [ $# -lt 2 ] ; then
        echo "Usage: `basename $0` <Filename> <Datafield8>"
else
        # initialize variable for filename
            file=$1

        # convert xml file in readable format
           xmllint --format $file > $file.tmp

        # split string from $2 in seperate variables
            IFS="/"
            Wert=$2
            set -- $Wert
            p9=$2
            p10=$1

        # simple sed replace but output to a new file
            sed 's@NEW@UPD@' $file.tmp > $file.tmp2
            sed 's@<PosReference number="9"/>@<PosReference number="9">'$p9'</PosReference>@' $file.tmp2 > $file.tmp3
            sed 's@<PosReference number="10"/>@<PosReference number="10">'$p10'</PosReference>@' $file.tmp3 > $file.tmp4

        # append prefix from original file name with "_script"

            new=`echo $file | sed 's@.xml@_script.xml@'`

        # check if $new is empty or not
            if [ -z "$new" ]
              then
                :
              else
                cp $file.tmp4 $new
            fi

        # delete all temporary files
            rm -f $file.tmp $file.tmp2 $file.tmp3 $file.tmp4
fi

Im Anschluss sehen alle Zeilen mit Ref 9 & 10 wie folgt aus:
Code:
          <PosReference number="9">0815</PosReference>
          <PosReference number="10">4711</PosReference>

Solange die Batch Nummer in der Datei überall gleich ist, reicht mir ein Parameter. Jedoch kommt es häufig vor, dass die Batch Nummer verschieden ist (siehe auch Beispiel oben) und demnach auch die Werte in Ref 9 & 10.
Nun würde ich gerne wissen, ob und vielleicht wie es möglich ist, mehrere Werte gleichzeitig zu ändern, je nachdem welche Batch Nummer man mit übergibt.

Dachte an einen Aufruf wie z.B.:
Code:
basename $0 <Filename> <batch#1> <parameter#1> <batch#2> <parameter#2> <batch#3> <parameter#3>

Das Skript sucht die gesamte Datei nach dem Wert batch#1 geht immer 14 bzw. 15 Zeilen runter und ändert dort den Wert für Ref 9 & 10 nach Vorgabe parameter#1. Das selbe dann für batch#2, batch #3 etc.

Hat jemand eine Idee?

Danke und Gruß
Jacko
 
geht problemlos - Du kannst ja auch die anderen Bereich in der RegEx mit Variablen erweitern.

Grundlegend würde ich Dir aber empfehlen, das nicht mit sed zu machen sondern dafür einen ded. xml-Bibliothek zu verwenden, in der Du ded. auf die einzelnen Elemente zugreifen kannst - php, perl können das wesentlich besser, auch für python oder andere Scriptsprachen findet sich sicher was.
 
Hallo marce,

habe bis dato noch nie ein Perl, Python o.ä. Skript erstellt. Von daher konnte ich nicht wirklich was mit deinem Beitrag anfangen. Habe mir jetzt mal auf die schnelle ein paar Perl Basics rausgesucht und folgendes Skript erstellt:

Code:
#!/usr/local/bin/perl -w

use strict;
use warnings;
use Tie::File;

my $inputfile = $ARGV[0];
my $batch1 = $ARGV[1];
my $param1 = $ARGV[2];
my $batch2 = $ARGV[3];
my $param2 = $ARGV[4];
my $arg_count = scalar @ARGV;

my @ref1;
my @ref2;

@ref1 = split(/\//, $param1);
if ($arg_count == 5) { @ref2 = split(/\//, $param2); }

my @records;
tie @records, 'Tie::File', $inputfile;

my $last_idx = $#records;

for (0 .. $last_idx) {
   if ($records[$_] =~ /$batch1/) {
      print "Vorher --> $records[$_+15]\n";
      $records[$_+15] =~ s@<PosReferenz nummer="9"/>@<PosReferenz nummer="9">$ref1[1]</PosReferenz>@g;
      print "Nachher --> $records[$_+15]\n";

      print "Vorher --> $records[$_+16]\n";
      $records[$_+16] =~ s@<PosReferenz nummer="10"/>@<PosReferenz nummer="10">$ref1[0]</PosReferenz>@g;
      print "Nachher --> $records[$_+16]\n";

      print "\n";
   }

   if ($records[$_] =~ /$batch2/) {
      print "Vorher --> $records[$_+15]\n";
      $records[$_+15] =~ s@<PosReferenz nummer="9"/>@<PosReferenz nummer="9">$ref2[1]</PosReferenz>@g;
      print "Nachher --> $records[$_+15]\n";

      print "Vorher --> $records[$_+16]\n";
      $records[$_+16] =~ s@<PosReferenz nummer="10"/>@<PosReferenz nummer="10">$ref2[0]</PosReferenz>@g;
      print "Nachher --> $records[$_+16]\n";

      print "\n";
   }
}

untie @records;

Ein Aufruf mit z.B.
Code:
perl test.pl myfile.xml 00320160501 0815/4711 00120160501 1234/5678
klappt ohne Probleme, jedoch habe ich noch ein paar kleinere Frage, die ich noch nicht gelöst bekommen habe.

1. Im Moment wird die Eingangsdatei überschrieben, möchte aber die Änderungen unter einem neuen Namen (myfile_change.xml) speichern. Wie geht das?

2. Ich möchte folgende Zeile
Code:
xmllint --format $inputfile
aus dem Shellskript auch unter Perl ausführen. Wie kann ich Bash Befehle unter Perl implementieren?

3. Folgende Codezeilen funktionieren anscheinend ohne Probleme:
Code:
@ref1 = split(/\//, $param1);
if ($arg_count == 5) { @ref2 = split(/\//, $param2); }

Ändere ich die erste Zeile auf
Code:
if ($arg_count == 3) { @ref1 = split(/\//, $param1); }

erhalte ich folgende Fehlermeldungen:
Use of uninitialized value $ref1[1] in concatenation (.) or string at cbrperl.pl line 36, <$fh> line 553.
Use of uninitialized value $ref1[0] in concatenation (.) or string at cbrperl.pl line 40, <$fh> line 554.

Wieso funktioniert die If-Prüfung nicht für ref1?

Gruß
Jacko
 
Hm, ich meinte eigentlich nicht, Du sollst das Script 1:1 von Shell-Code in Perl-Code übersetzen.

Du sollst eine Bibliothek verwenden, welche direkt in den XML-Strukturen arbeitet.
 
Na ja, mit der Umwandlung in Perl hat das ja auch ganz gut funktioniert ;)
Wenn ich noch die drei Punkte gelöst bekomme, speziell 1 und 2, dann bin ich auch zufrieden und habe nebenbei noch ein wenig Perl gelernt :)
 

Ähnliche Themen

E/A-Fehler (.snapshots is not a btrfs subvolume).

[Perl] Perl OO Methodenaufruf in anderem Objekt

Rollei Mini Wifi Camcorder

Akonadi startet nicht mehr

Gnome Classic Desktop: Home-Inhalt Icons ausblenden

Zurück
Oben