2016-09-26 4 views
1

Hallo Ich habe diese beiden Dateien:vergleichen Dateien awk, drucken Spiele und verketten, wenn es mehr als ein Spiel ist

cat file1.tab 
1704 1.000000 T G 
1708 1.000000 C G 
1711 1.000000 G C 
1712 0.989011 T A 
1712 0.003564 T G 

cat file2.tab 
1704 
1705 
1706 
1707 
1708 
1709 
1710 
1711 
1712 
1713 

ich diese Ausgabe möchte:

1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.003564 T G 0.003564 T G 
1713 0 

konnte ich fast bekommt es mit diesem:

awk 'NR==FNR { a[$1]=$0;b[$1]=$1; next} { if ($1 == b[$1]) print a[$1]; else print $1,"0";}' file1.tab file2.tab 

Aber ich weiß nicht, wie mit Wiederholungen zu tun .. Mein Skript prüft nicht, ob die Zeichen in Spalte 1 in file1.tab wird wiederholt, so dass er die $ 0 nur das letzte Mal gibt es scheint ...

+0

Sie wollen eine [$ 1] nicht überschreiben sie anhängen. – 123

+0

Ausgabe der Zeile beginnt mit '1712' fehlt' 0.989011' – anubhava

Antwort

2

Sie dieses awk verwenden können:

awk 'FNR==NR{a[$1] = (a[$1]==""?"":a[$1] " ") $2 OFS $3 OFS $4; next} 
    {print $1, ($1 in a ? a[$1] : 0)}' file1 file2 

1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 

Referenz:Effective AWK Programming Wie es funktioniert:

  • FNR==NR - Führen Sie diesen Block für file1 nur
  • a[$1] = (a[$1]==""?"":a[$1] " ") $2 OFS $3 OFS $4 - Erstellen Sie ein assoziatives Array a mit Schlüssel als $1 und Wert als $2 + $3 + $4 (halten vorherigen Werte angehängt)
  • next - überspringen zum nächsten Rekord
  • {...} - Führen Sie diesen Block für die 2. Eingabedatei file2
  • if ($1 in a) wenn $1 2. Datei a
  • print $1, ($1 in a ? a[$1] : 0 in aray existiert - $1 und den Wert aus dem Feld drucken, wenn $1 in a sonst 0 wird gedruckt.
+1

Funktioniert perfekt! Vielen Dank! Könnten Sie bitte eine kurze Erklärung hinzufügen? – user3666956

+1

Ich habe eine Erklärung als Antwort hinzugefügt. – anubhava

2

Man könnte so etwas wie folgt verwenden:

$ awk 'NR==FNR{$1=$1 in a?a[$1]:$1;$0=$0;a[$1]=$0;next}{print $1 in a?a[$1]:$1 OFS 0}' file1.tab file2.tab 
1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 

Eine Erklärung, wie das funktioniert:

  • Dieser Block 'NR==FNR{$1=$1 in a?a[$1]:$1;$0=$0;a[$1]=$0;next} bei der ersten Datei ausgeführt wird, in dem der Datensatzindex gleich der Datensatzindex. Also setzen wir für die erste Datei das erste Wort auf den im Array gespeicherten Wert, falls einer existiert, oder andernfalls auf das erste Wort. Dann teilen wir die Felder mit $0=$0 erneut auf, da das erste Feld jetzt mehrere Wörter enthalten kann. Danach speichern wir die Zeile im Array mit dem ersten Wort als Index
  • Der Baustein {print $1 in a?a[$1]:$1 OFS 0}' wird nur für die Zeilen der zweiten Datei ausgeführt (aufgrund der next Anweisung im vorherigen Block). Wenn wir eine übereinstimmende Zeile finden, drucken wir sie, andernfalls conchatenale 0 mit dem ersten Wort, und drucken.
+0

Das ist großartig! Könnten Sie bitte eine kurze Erklärung hinzufügen? – user3666956

+1

@ user3666956: Eine kleine Erklärung hinzugefügt. Lassen Sie mich wissen, ob noch etwas für Sie unklar ist. – user000001

+0

Thx, jetzt ist es klar für mich! – user3666956

1

Mit perl

$ perl -F'/\s+/,$_,2' -lane ' 
    if(!$#ARGV){ $h{$F[0]} .= $h{$F[0]} ? " $F[1]" : $F[1] } 
    else{ print "$F[0] ", $h{$F[0]} ? $h{$F[0]} : 0 } 
    ' file1.tab file2.tab 
1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 
  • -F'/\s+/,$_,2' Split-Eingangsleitung auf Leerzeichen, maximal 2 Felder
  • !$#ARGV wird
  • %h hash variable NR==FNR für zwei Dateibefehlszeilenargumente awk die ähnlich arbeiten speichert angehängte Werte basierend auf dem ersten Feld als Schlüssel
  • Wenn die zweite Datei verarbeitet wird, drucken, wie pro erforderlichem Format
  • -l Option Streifen newlines von Eingangsleitungen und fügt neue Zeilen zu jeder print Anweisung
0

Hier ist ein Produkt eines unaufhaltsamen Denkprozesses ist mit join, uniq, tac, grep und sort. Die Idee besteht darin, die eindeutigen Schlüssel/Wert-Paare zu erhalten (insbesondere für den Schlüssel 1712) und diese zu verbinden, um Zeilen wie 1708 1.000000 C G 1.000000 C G zu vermeiden, so dass diese Lösung das Gruppieren von drei oder mehr Werten pro Schlüssel nicht unterstützt. join -o ... -e "0" würde auch nicht nur 1 0 für die nicht verbindenden Zeilen erzeugen, weil file1.tab 3 Spalten haben, um zu verbinden.

$ join -a 1 <(join -a 1 file2.tab <(uniq -w 4 file1.tab)) <(grep -v -f <(uniq -w 4 file1.tab) <(tac file1.tab|uniq -w 4|sort)) 
1704 1.000000 T G 
1705 
1706 
1707 
1708 1.000000 C G 
1709 
1710 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 

Strukturiertere Layout:

$ join -a 1 
      <(join -a 1 
         file2.tab 
         <(uniq -w 4 file1.tab)) 
      <(grep -v -f 
         <(uniq -w 4 file1.tab) 
         <(tac file1.tab|uniq -w 4|sort)) 
Verwandte Themen