Umgang mit 3 Dateien mit awk

9

Betrachten Sie folgende Dateien:

file1::

boo,8,1024
foo,7,2048

file2::

foo,0,24,154
noo,0,10,561

file3::

24,154,7,1024,0

Was ich brauche, ist zu Datei1 zu gehen und zu überprüfen, ob $2==7; wenn sie wahr sind , nehmen $1, $2und $3von File1 ; jetzt muss ich vergleichen, ob $1von Datei1 gleich $1von Datei2 ist ; wenn das stimmt, muss ich nehmen $3und $4von File2 , die existieren nicht in File1 , dann muss ich gehen File3 und prüfen , ob $1von File3 gleich $3von File2 und $2von File3 ist gleich $4von File2 ; Wenn ja, muss ich überprüfen, ob $2aus Datei1ist gleich $3von File3 , dann, wenn diese Bedingung wahr ist, muss ich $3von File1 mit $4von File3 vergleichen , wenn $3von File1 mehr ist als $4von File3 .

Ich habe folgendes Skript ausprobiert:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

Die gewünschte Ausgabe ist:

foo,7,2048,24,154,1024
Eng7
quelle

Antworten:

9

Das hat bei mir funktioniert:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

Erklärung :

  • Die erste Zeile ( FNR==1{++f}) erhöht den Dateiindex, um später zu bestimmen, in welcher Datei wir 1-3 sind.
  • Datei1: wenn $2gleich7
    • ein Array füllen a1mit $1als Index und a2mit $2als Index und $3als Wert
    • Schreiben Sie die oVariable (Ausgabe) mit den ersten 3 Feldern auf
  • file2: wenn $1die file2Gleichen $1von file1(prevously geschrieben a1)
    • anhängen $3und $4an die Ausgabevariable o.
    • Füllen Sie ein Array a3mit $3als Index und $4als Wert.
  • Datei3: wenn:
    • $1entspricht file2s $3(Index von a3)
    • $2entspricht file2s $4(Wert von a3)
    • $3entspricht file1s $2(Index von a2)
    • $4ist niedriger als file1s $3(Wert von a2)
  • dann:
    • Drucken Sie den Wert von o.
Chaos
quelle
Gibt es einen Backslash (abgesehen vom letzten)? Wie wäre es mit BEGINFILE (anstelle von FNR == 1)?
Archemar
@Archemar BEGINFILE und ENDFILE sind Gawk-Erweiterungen und die Backslashes können alle entfernt werden, ich habe sie eingefügt, um die Lesbarkeit zu verbessern: Sie können das Ganze in einer einzigen Zeile schreiben, aber es würde nicht gut aussehen
Chaos
@chaos, danke, aber leider gibt es immer null zurück.
Eng7
@ Azizieh7 Ich habe es mit mawk und gawk mit deinen 3 Eingabebeispieldateien getestet. Bei mir hat es geklappt. Verwenden Sie unterschiedliche Eingabedateien oder Codierungen / Zeilenumbrüche?
Chaos
@chaos, es gibt verschiedene Zeilenumbrüche in Datei3, aber ich benutze tr -d '\ 015', um dies zu überwinden.
Eng7
1

TXR-Lösung:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

Lauf:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

Der scharfsinnige Beobachter wird jedoch feststellen, dass die 7 nirgendwo im Code angegeben wurde und nur in der Ausgabe erscheint! Dies liegt daran, dass der Code tatsächlich durch alle Datensätze in marschiert file1und alle Kombinationen druckt, die den Übereinstimmungen und Einschränkungen entsprechen . Der einzige in den Beispieldaten ist der mit dem val0Sein 7.

Wenn mehr Kombinationen gefunden würden, könnte dies auf die folgende beschränkt werden 7:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

Die TXR-Musterextraktionssprache bietet hier eine große Musterübereinstimmung mit impliziten Rückverweisen durch Wiederholung von Variablennamen, die mehrere Dateien umfassen, mit mehrzeiligen Extraktionsmustern und nicht-textuellen Einschränkungen sowie eingebetteten Nebenwirkungen wie Ausgabe usw. .

Akzeptierte Awk-Lösung übersetzte das TXR Lisp- awkMakro sorgfältig :

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

Lauf:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

Der ,1024erforderliche Teil in der Ausgabe fehlt. Das Original "Awk Classic" hat dieses Verhalten.

Kaz
quelle