Werte addieren über Dateigrenzen hinweg

Dieses Thema im Forum "Shell-Skripte" wurde erstellt von elyps, 12.01.2010.

  1. #1 elyps, 12.01.2010
    Zuletzt bearbeitet: 12.01.2010
    elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Hallo,

    ich hoffe, dass der Titel das Problem bereits deutlich macht.

    Ich habe mehrere ASCII-Dateien, die jeweils 21x21 Zahlenwerte beinhalten. Ich möchte nun beliebige Dateien "addieren", also diese Matrizen addieren.

    Ich habe leider nichts zu diesem spezifischen Fall gefunden, sondern immer nur das (für mich) recht umständliche Addieren mittels awk:
    Code:
    #!/bin/awk -f
    BEGIN{OFS="\t";}
    {column1[FNR]+=$1;column2[FNR]+=$2;column3[FNR]+=$3;}
    END {
    for (i in column1) {print i, column1[i], column2[i], column3[i]}
    }
    
    Bei dieser Methode muss ich aber alle columns manuell angeben. Das erscheint mir nicht gerade effektiv.

    Weiß jemand von euch Hilfe? Danke.
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 slackfan, 12.01.2010
    Zuletzt bearbeitet: 12.01.2010
    slackfan

    slackfan König

    Dabei seit:
    18.04.2006
    Beiträge:
    809
    Zustimmungen:
    0
    Ort:
    Bonn
    Keine Ahnung, ob das für dich brauchbar ist. Geht sicher viel schöner. Habe es jetzt nur von etwas bestehendem abgeleitet und hingefrickelt.

    Code:
    #!/usr/bin/ruby
    
    # Usage: add_matrix.rb eins.txt zwei.txt [drei.txt ...]
    
    add_matrix = []
    width_matrix = 21
    
    if __FILE__== $0
      # Read input
      if ARGV.length > 1
          ARGV.each do |file|
          if FileTest.readable?(file)
            pos = 0
            File.read(file).scan(/[\d]{1,4}/).each do |element|
              if add_matrix[pos]
                add_matrix[pos] += element.to_i
              else
                add_matrix[pos] = element.to_i
              end
              pos += 1
            end
          end
        end
      end
    
      # Form and print output
      pos = 0
      add_matrix.each do |element|
        pos += 1
        print element
        if pos == width_matrix
          print "\n"
          pos = 0
        else
          print "\t"
        end
      end
    
    end
    
    cu
     
  4. #3 floyd62, 13.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Schnellschuss, aber probier doch mal so was:
    Code:
    #!/bin/bash
    
    exec 3<$1
    exec 4<$2
    
    while read L1 <&3; read L2 <&4; do
            set -- $L1
            for N in $L2; do
                    echo -n "$(($1 + $N)) "
                    shift
            done
            echo
    done
    
    Gruss, A.
     
  5. elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    So, jetzt komme ich endlich mal zum Ausprobieren...

    Ein Aufruf dieses Skripts mit den beiden Matrizen als Argumente führt zu folgender Fehlermeldung:
    Code:
    ./matrix_addition.sh: Zeile 9: 8.382520E-09 + 3.914659E-09:
    Syntaxfehler: Ungültiger arithmetischer Operator.
    (error token is ".382520E-09 + 3.914659E-09")
    
    hmm, kapiere ich nicht so ganz... wieso wird der erste Wert nicht vollständig wiedergegeben?
     
  6. #5 floyd62, 15.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    War halt ein Schnellschuss ;-)

    Problem ist, dass die Shell intern nur Arithmetik mit Ganzzahlen beherrscht. Daher zeigt er dir den Teil der ersten Zahl ab dem Dezimaltrenner als Fehler an.

    Wenn du also in o.a. Skript die Zeile
    Code:
    echo -n "$(($N + $1)) "
    
    durch
    Code:
    echo $N $1 | awk '{ printf "%e ", $1 + $2; }'
    
    ersetzt, sollte das schon mal ein bisschen besser laufen. Das Problem ist dann allerdings, dass du bei den 21x21-Matrizen mehr als 400-mal den awk bemühst ...

    Innerhalb eines awk-Skripts sollte es wohl möglich sein, mit "getline" jeweils eine Zeile aus der ersten und zweiten Eingabedatei zu lesen.

    Ein anderer Versuch wäre evtl, zunächst mit "paste" die beiden Matrizen zeilenweise zusammenzufassen, und dann mit "awk" zu verarbeiten:
    Code:
    #!/bin/sh
    
    paste $1 $2 |
    awk '{
            for (i = 1; i <= NF/2; i++) {
                    j = i + NF/2;
                    printf "%e%s", $i + $j, i < NF/2 ? "\t" : "\n";
            }
    }'
    
    Gruss
     
  7. #6 elyps, 18.01.2010
    Zuletzt bearbeitet: 18.01.2010
    elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Hallo floyd62.

    Vielen Dank! Das ist echt super und noch besser... es funktioniert! :-)

    Hast Du noch ne Idee, wie ich dem Skript sagen kann, dass es immer mehrere Dateien, die den gleichen Namen haben, addieren soll? Konkret habe ich vier Ordner und in jedem dieser Ordner liegen dutzende Dateien, die jeweils gleich benannt sind... nun will ich dem Skript sagen, dass es sich jeweils die gleich-benannten Dateien aus diesen Ordnern holt, diese dann addiert (nach obigem Modell) und das Ergebnis unter einem neuen Namen in einen neuen (fünften) Ordner speichert.

    Ich weiß... eine sehr spezielle Frage, sorry.

    Gruss.
     
  8. #7 floyd62, 18.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    ... einfach ' ne kleine Schleife um den awk von oben:
    Code:
    IN1=...
    IN2=...
    OUT=...
    
    for F1 in IN1/*; do
            B=$(basename "$F1")
            F2=IN2/$B
            [ -f "$F2" ] || continue
            paste "$F1" "$F2" |
            awk '
                    for (i = 1; i <= NF/2; i++) {
                            j = i + NF/2;
                            printf "%e%s", $i + $j, i < NF/2 ? "\t" : "\n";
                    }
            ' > $OUT/$B
    done
    
    Wie immer: ungetestet ...

    Gruss
     
  9. elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Hi floyd62,

    ich weiß nicht woran es liegt, weil es keine Fehlermeldung gibt, aber es passiert anscheinend nix bei dem obigen Skript.

    Viele Grüße.
     
  10. #9 floyd62, 19.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Bei der Verwendung der IN1 und IN2-Variablen oben fehlt jeweils der $, sollte also z.B. so aussehen
    Code:
    for F in $IN1/*; do
    ...
            F2=$IN2/$B
    
    um die Dateien in den Verzeichnissen $IN1 und $IN2 zu addieren und das Ergebnis nach $OUT zu schieben. Die übrigen Bastelarbeiten (temporäre Dateien definieren, wenn du die Matrizen aus 4 Verzeichnissen addieren willst etc.) überlasse ich dir dann aber selbst ...

    Grüsse
     
  11. elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Hi,

    vielen Dank, das hatte ich übersehen mit dem $. Ich danke Dir sehr für Deine Hilfe und würde es ja auch gerne erweitern, aber ich seh den Wald vor lauter Bäumen nicht, wie mir scheint. Eigentlich ist es ja ganz einfach... das Pasten mittels
    Code:
    paste $1 $2 |
    awk '{
            for (i = 1; i <= NF/2; i++) {
                    j = i + NF/2;
                    printf "%e%s", $i + $j, i < NF/2 ? "\t" : "\n";
            }
    }'
    
    klappt wunderbar, aber für die Schleife kommt ein Synthaxfehler:
    Code:
    awk: line 2: syntax error at or near for
    
    für jede Datei, die aus der Addition entsteht. Die Dateien werden zwar in dem neuen Ordner angelegt, sind aber alle leer :-(

    Viele Grüße.
     
  12. #11 floyd62, 19.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Zeig doch einfach mal das ganze Skript, das du bisher hast. Der Teil, den du in deiner letzten Nachricht zitierst, läuft bei mir hier einwandfrei .... aber der verarbeitet ja weder Dateien aus irgendwelchen Ordnern, noch legt er Ausgabedateien in einem anderen Verzeichnis ab. Ich vermute also doch, dass der eigentliche Fehler ganz woanders liegt.

    Gruss
     
  13. elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Ja, der letzte Teil läuft bei mir auch, wenn ich im als Argument zwei Dateien zum Addieren gebe. Das gesamte Skript allerdings
    Code:
    #!/bin/bash
    
    IN1=45_auswertung	
    IN2=135_auswertung
    OUT=test
    
    for F1 in $IN1/*; do
            B=$(basename "$F1")
            F2=$IN2/$B
            [ -f "$F2" ] || continue
            paste "$F1" "$F2" |
            awk '
                    for (i = 1; i <= NF/2; i++) {
                            j = i + NF/2;
                            printf "%e%s", $i + $j, i < NF/2 ? "\t" : "\n";
                    }
            ' > $OUT/$B
    done
    
    spuckt den besagten Fehler aus. Zumindest legt er schon einmal leere Dateien an, prinzipiell läuft es also ;-)

    Viele Grüße.
     
  14. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  15. #13 floyd62, 20.01.2010
    Zuletzt bearbeitet: 20.01.2010
    floyd62

    floyd62 Routinier

    Dabei seit:
    01.05.2007
    Beiträge:
    309
    Zustimmungen:
    0
    Du hast im awk-Skript die Klammern { und } um die for-loop entfernt; das kann so nicht laufen! Abändern wie folgt:
    Code:
            awk '{
                    for (i = 1; i <= NF/2; i++) {
                            j = i + NF/2;
                            printf "%e%s", $i + $j, i < NF/2 ? "\t" : "\n";
                    }
            }' > $OUT/$B
    
    und nochmal versuchen ...
     
  16. elyps

    elyps Jungspund

    Dabei seit:
    20.10.2004
    Beiträge:
    12
    Zustimmungen:
    0
    Oh mann... bin ich ein Blindfisch. Es klappt jetzt. Danke!

    Gruss.
     
Thema:

Werte addieren über Dateigrenzen hinweg

Die Seite wird geladen...

Werte addieren über Dateigrenzen hinweg - Ähnliche Themen

  1. Free Software Foundation bewertet Codehosting-Dienste

    Free Software Foundation bewertet Codehosting-Dienste: Die Free Software Foundation (FSF) hat Bewertungen nach den selbst definierten Richtlinien für mehrere Codehosting-Dienste herausgegeben....
  2. Mit bash Skript bestimmte Werte aus Tabelle lesen

    Mit bash Skript bestimmte Werte aus Tabelle lesen: Hallo! Ich beschäftige mich erst seit Kurzem mit bash und bin deshalb noch nicht so fit darin. Und nun habe ich schon ein kleines Problem und...
  3. Logs von debsecan, tiger, chkrootkit richtig auswerten.

    Logs von debsecan, tiger, chkrootkit richtig auswerten.: Hallo! ich habe debsecan drüber laufen lassen und der zeigt mir einen Haufen an low/medium/high urgency an, mit oder ohne remotly exploitable....
  4. Wertebereich ersetzen mit sed

    Wertebereich ersetzen mit sed: Hallo Forenmitglieder, ich habe ein kleines Problem mit sed und zwar möchte ich in einer Datei mit mehren Spalten und Zeilen das Vorkommen eines...
  5. Jasper: Sprachsteuerung für preiswerte Rechner

    Jasper: Sprachsteuerung für preiswerte Rechner: Charlie Marsh und Shubhro Saha, Studenten der Princeton-Universität, haben mit Jasper eine Open-Source-Anwendung veröffentlicht, mit deren Hilfe...