awk: Extrahieren Sie tabulatorgetrennte Spalten, die mit den Teilzeichenfolgen in der ersten Zeile übereinstimmen

awk: Extrahieren Sie tabulatorgetrennte Spalten, die mit den Teilzeichenfolgen in der ersten Zeile übereinstimmen

Ich möchte tabulatorgetrennte Spalten aus einer Textdatei („columns.txt“) extrahieren, deren Kopfzeile (erste Zeile) mit bestimmten Zeichenfolgen übereinstimmt, die in einer anderen Textdatei („strings.txt“) aufgeführt sind.

"columns.txt" sieht folgendermaßen aus:

rs2438689   rs54666437   rs9877702046   rs025436779...
0           0            0              1
1           1            2              2 
0           1            2              0 
...         ...          ...            ...

"strings.txt" sieht folgendermaßen aus:

rs2438689
rs9877702046   
...

Die Ausgabetextdatei „output.txt“ sollte wie folgt aussehen (Tabulator-getrennt):

rs2438689   rs9877702046...
0           0              
1           2               
0           2               
...         ...    

Irgendwelche Vorschläge, wie man das mit awk macht? Danke!

Antwort1

Wie wäre es, statt Awk eine durch Kommas getrennte Liste mit Spaltennamen aus zu erstellen strings.txtund diese als Liste mit namedcols für zu verwenden csvtool:

$ csvtool -t TAB -u TAB namedcol "$(paste -sd, < strings.txt)" columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

oder ähnlich mit csvcut/csvformatdem Python-basierten csvkit:

$ csvcut -tc "$(paste -sd, < strings.txt)" columns.txt | csvformat -T
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

Antwort2

Mitperl

$ perl -F'\t' -lane 'if(!$#ARGV){ $h{$_}=1 }
                     else{ @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++;
                           print join "\t", @F[@i]}' strings.txt columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
  • if(!$#ARGV){ $h{$_}=1 }Erstellen Sie für die erste Eingabedatei einen Hash mit Zeileninhalt als Schlüssel
  • @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++Erstellen Sie für die erste Zeile der zweiten Datei eine Indexliste aller übereinstimmenden Spaltennamen aus dem Hash
  • print join "\t", @F[@i]Drucken Sie die passenden Spalten

Antwort3

Ändernmeine Lösung für deine vorherige Frage:

awk -F '\t' -f script.awk strings.txt columns.txt

wo script.awkist

BEGIN { OFS = FS }

FNR == NR {
    columns[$1] = 1
    next
}

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

{
    nf = split($0, fields, FS)
    $0 = ""
    j = 0

    for (i = 1; i <= nf; ++i)
        if (i in keep)
            $(++j) = fields[i]

    print
}

Hier FNR == NRwürde der Block nur ausgeführt, wenn aus der ersten in der Befehlszeile aufgeführten Datei gelesen wird ( strings.txt). Er würde das columnsArray mit Schlüsseln füllen, die die Namen der Spalten sind. Der Rest des Codes istmehr oder wenigerFNR == 1unverändert gegenüber der alten Lösung, abgesehen davon, wo wir prüfen, ob es sich bei der aktuellen Spalte um eine handelt, die wir (im Block) behalten möchten .


Adressierung derFragen in Kommentaren:

Um immer die ersten sechs Spalten zu kopieren und die Spaltenüberschriften bei abzuschneiden _, ändern Sie

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

hinein

FNR == 1 {
    for (i = 1; i <= NF; ++i) {
        sub("_.*", "", $i)
        if (i <= 6 || $i in columns)
            keep[i] = 1
    }
}

Antwort4

Mit dem folgenden Skript erledigt, es kann lange dauern, aber es hat gut funktioniert

k =wc -l file1| awk '{print $1}'

for ((i=1;i<=$k;i++));  do for j in `cat file2`; do awk -v i="$i" -v j="$j" '$i == j {x=NR+k}(NR<=x){print $i}' file1; done ; done>final.txt

z=`wc -l final.txt| awk '{print $1}'`

for ((i=1;i<=$z;i++)); do j=$(($i+3)); sed -n ''$i','$j'p' final.txt >file_starting_with_$i.txt; i=$j; done

paste file_starting_with*

Ausgabe

rs2438689   rs9877702046
0       0
1       2
0       2

verwandte Informationen