Anzeige:
Ergebnis 1 bis 8 von 8

Thema: Bash: Daten verarbeiten, sortieren und zuordnen.

  1. #1
    Registrierter Benutzer
    Registriert seit
    23.05.2007
    Beiträge
    21

    Bash: Daten verarbeiten, sortieren und zuordnen.

    Hallo,
    ich brauche einen Tipp, wie ich folgenden Daten verarbeiten kann:

    Artikelname1 Zeitung
    Artikelname1 Buch
    Artikelname1 Grußkarten
    Quantity1 1.00
    Quantity1 2.00
    Quantity1 1.00
    Price1 32.96
    Price1 41.20
    Price1 74.16

    Ich möchte jedes Werte paar als einen Datensatz verarbeiten:
    Variablen: artikelname;quantity;price
    Datensatz 1: Zeitung; 1.00; 32.96;
    Datensatz 2: Buch; 2.00; 41.20;
    Datensatz 3 Grußkarten; 1.00; 74.16;
    In dem Text können auch mehr als 3 oder auch nur 2 Wertepaare enthalten sein.
    Die Werte will ich in eine DB eintragen, wie das geht, weis ich.


    Mein Ansatz ist zu Zählen, wie viel mal z.B. Artikelname1 vorkommt.

    Aber wie geht es denn weiter?
    Ich brauche dringend einen Ansatz.

    Danke für Eure Hilfe!

    Gruß
    Tino Brandt

  2. #2
    Registrierter Benutzer Avatar von Aqualung
    Registriert seit
    28.01.2008
    Beiträge
    14
    Die Zuordnung ist ausschließlich über die Reihenfolge festgelegt?

  3. #3
    Registrierter Benutzer
    Registriert seit
    23.05.2007
    Beiträge
    21
    Ja,

    die erste Position bildet ein Wertepaar (Zeitung;1.00;32.96), jeweils die zweite usw.



    Danke!

    Gruß
    Tino

  4. #4
    Registrierter Benutzer Avatar von Aqualung
    Registriert seit
    28.01.2008
    Beiträge
    14
    Deine Eingabe sei file3. Eine "hölzerne" Lsg. wäre:

    Code:
    mytmp=$(mktemp -d)
    grep Artikelname1 file3 | cut -d" " -f2 > $mytmp/1.tmp
    grep Quantity1    file3 | cut -d" " -f2 > $mytmp/2.tmp
    grep Price1       file3 | cut -d" " -f2 > $mytmp/3.tmp
    
    paste $mytmp/1.tmp $mytmp/2.tmp $mytmp/3.tmp
    
    Zeitung 1.00    32.96
    Buch    2.00    41.20
    Grußkarten      1.00    74.16
    
    rm -rf $mytmp

  5. #5
    Registrierter Benutzer
    Registriert seit
    23.05.2007
    Beiträge
    21

    Smile

    Super, danke für den Ansatz.
    Ich will ja die Werte in eine DB erfassen, mal sehen wie ich die Zuordnung hinbekommen.

    Nochmals Danke!

    Gruß
    Tino

  6. #6
    Registrierter Benutzer
    Registriert seit
    23.05.2007
    Beiträge
    21
    Hier meine daraus entwickelte Lösung:

    ##
    mytmp=$(mktemp -d)
    grep Artikelname1 file3 | cut -d" " -f2 > $mytmp/1.tmp
    grep Quantity1 file3 | cut -d" " -f2 > $mytmp/2.tmp
    grep Price1 file3 | cut -d" " -f2 > $mytmp/3.tmp

    anzahl=$(cat file3 | grep "Artikelname1" | wc -l)

    for ((m=1; $m<=$anzahl; m++));do
    artikelname=$(head -n$m $mytmp/1.tmp | tail -n1)
    echo $artikelname
    quantity=$(head -n$m $mytmp/2.tmp | tail -n1)
    echo $quantity
    price=$(head -n$m $mytmp/3.tmp | tail -n1)
    echo $price
    done
    rm -rf $mytmp
    ##

    Gruß
    Tino

  7. #7
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    hm, das ist eine ziemlich aufwändige Variante. Ich würde hier eher mit Bash-Arrays oder mit awk (in dem Arrays auch möglich sind) arbeiten.

    Ich hatte die Behandlung von Arrays im awk neulich schon mal gezeigt, hier eine angepasste Version:
    Code:
    jan@jack:~/tmp/kv2csv> cat datei
    Artikelname1 Zeitung
    Artikelname1 Buch
    Artikelname1 Grußkarten
    Quantity1 1.00
    Quantity1 2.00
    Quantity1 1.00
    Price1 32.96
    Price1 41.20
    Price1 74.16
    jan@jack:~/tmp/kv2csv> cat kv2csv.awk
    { if (z_arr[$1] == "") z_arr[$1] = 0;   # z_arr: key=variable, value=wertzaehler
      else z_arr[$1]++;
      f_arr[$1,z_arr[$1]] = $2;             # f_arr: key=variable+zaehler, value=wert
    }
    END {                                   # einlesen beendet: ausgabe
      out = "";                             # ausgabezeile
      max = 0;                              # hoechster zaehler
      for (z in z_arr) {                    # schleife fuer header: alle variablen
        out = out z ";";                    # an ausgabe variable + ";" anhaengen
        if (max < z_arr[z]) max = z_arr[z]; # max hochzaehlen
      }
      gsub(/;$/, "", out);                  # letztes ; entfernen
      print out;                            # ausgeben
      for (c = 0; c <= max; c++) {          # schleife ueber alle zaehler
        out = "";                           # ausgabezeile
        for (z in z_arr) {                  # schleife ueber alle variablen
          out = out f_arr[z,c] ";";         # an ausgabe wert + ; anhaengen
        }
        gsub(/;$/, "", out);                # letztes ; weg
        print out;                          # ausgeben
      }
    }
    
    jan@jack:~/tmp/kv2csv> awk -f kv2csv.awk datei
    Quantity1;Artikelname1;Price1
    1.00;Zeitung;32.96
    2.00;Buch;41.20
    1.00;Grußkarten;74.16
    Vorteil: Kommt mit beliebigen Variablennamen (und beliebiger Anzahl Variablen und Werte) klar, kommt ohne temp. Dateien aus, nur 1 Prozess statt vieler (nach meiner Zählung 17 Prozesse + 8 Subshells durch die Pipes), wahrscheinlich deutlich schneller - vor allem bei größeren Dateien.

    Jan

    P.S.: Bitte bitte - lasst diese unsäglichen Konstruktionen wie 'cat file3 | grep "Artikelname1" | wc -l'! Der grep kann - wie die meisten Unix-Kommandos - Dateinamen als Kommandozeilenargument verarbeiten, da ist kein cat vorneweg nötig. Und mit einem Blick in die grep-Manualpage hätte sich die Option -c geradezu aufgedrängt. Das Ganze ließe sich also unter Einsparung von 2 Prozessen und 2 Subshells einfach als 'grep -c "Artikelname1" file3' schreiben.

    EDIT: Die Anzahl Prozesse + Subshells in Deiner Lösung sind die Minimalwerte bei 1 Wert. Mit jedem weiteren Schleifendurchlauf kommen 6 Prozesse und 3 Subshells dazu.
    Geändert von jan61 (07-07-2008 um 20:10 Uhr)

  8. #8
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    der Vollständigkeit halber hier noch 2 Varianten mit bash-Arrays. Ich musste für die 2. (flexible) Version etwas basteln, deshalb die Verspätung ;-)

    1. Version: Die Feld(Variablen)-Namen sind bekannt und festgelegt. Ich nutze fest definierte bash-Arrays, die maximale Anzahl von Werten ermittle ich gleich in der 1. Schleife, um mir extra Berechnungen zu ersparen. Das Script sollte relativ einfach zu verstehen sein:
    Code:
    jan@jack:~/tmp/kv2csv> cat kv2csv.sh
    #! /bin/bash
    
    declare -a Artikelname1
    declare -a Quantity1
    declare -a Price1
    
    max=0
    while read k v; do
      case $k in
        Artikelname1)
          n=${#Artikelname1[*]}
          Artikelname1[$n]="$v"
          ;;
        Quantity1)
          n=${#Quantity1[*]}
          Quantity1[$n]="$v"
          ;;
        Price1)
          n=${#Price1[*]}
          Price1[$n]="$v"
          ;;
      esac
      test $max -lt $n && max=$n
    done <datei
    
    echo "Artikelname1;Quantity1;Price1"
    for i in `seq 0 $max`; do
      echo "${Artikelname1[$i]};${Quantity1[$i]};${Price1[$i]}"
    done
    
    exit 0
    Die 2. Version ist ziemlich schwer verdaulich, zeigt aber, wie man auch in der bash mit variablen Variablennamen arbeiten kann ;-) Das wichtigste Shell-Builtin für solche Anwendungen ist eval, das einen übergebenen Ausdruck evaluiert (in der Shell ausführt). Den zu evaluierenden Ausdruck setze ich mit diversen echo-Kommandos zusammen:
    Code:
    jan@jack:~/tmp/kv2csv> cat kv2csv_var.sh
    #! /bin/bash
    
    max=0
    vars=" "
    while read k v; do
      echo "$vars" | grep -q " $k " || vars="$vars$k "
      m=`eval echo \`echo '${#'$k'[*]}'\``
      test $max -lt $m && max=$m
      eval `echo \`echo $k'['$m']='"$v"\``
    done <datei
    echo "$vars"
    
    echo $vars | sed 's/ /;/g'
    for i in `seq 0 $max`; do
      out=""
      for k in $vars; do
        v="`eval echo \`echo '${'$k'['$i']}'\``"
        if test -n "$out"; then
          out="$out;$v"
        else
         out="$v"
        fi
      done
      echo "$out"
    done
    
    exit 0
    Das Ding ist sogar kürzer als die 1. Version, aber flexibel bei Anzahl und Namen der Variablen - man muss nur ziemlich lange grübeln, bis man hinter die Funktion kommt ;-) Um die Funktionsweise zu verstehen, solltet Ihr ein "set -x" an den Anfang des Scripts setzen, dann wird Euch jeder Schritt angezeigt.

    Man kann noch ein wenig vereinfachen und Prozesse sparen, wenn man die Möglichkeiten der bash ausreizt (der grep könnte u. U. durch ${parameter/pattern/string} ersetzt werden, die for-Schleife im Old-Unix-Style durch die C-Style-Variante, ...).

    Jan

    EDIT: Die 2. Variante habe ich unnötig kompliziert gemacht (so kommt das, wenn man bastelt und bastelt und die Leichen drin lässt). So sieht es viel einleuchtender aus:
    Code:
    jan@jack:~/tmp/kv2csv> cat kv2csv_var.sh
    #! /bin/bash
    
    max=0
    vars=" "
    while read k v; do
      echo "$vars" | grep -q " $k " || vars="$vars$k "
      m=`eval echo '${#'$k'[*]}'`
      test $max -lt $m && max=$m
      eval $k'['$m']='"$v"
    done <datei
    
    echo $vars | sed 's/ /;/g'
    for i in `seq 0 $max`; do
      out=""
      for k in $vars; do
        v="`eval echo '${'$k'['$i']}'`"
        test -n "$out" && out="$out;"
        out="$out$v"
      done
      echo "$out"
    done
    
    exit 0
    Geändert von jan61 (07-07-2008 um 22:41 Uhr) Grund: Geht auch viel einfacher

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •