
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.txt
und diese als Liste mit namedcol
s 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/csvformat
dem 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 Hashprint 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.awk
ist
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 == NR
würde der Block nur ausgeführt, wenn aus der ersten in der Befehlszeile aufgeführten Datei gelesen wird ( strings.txt
). Er würde das columns
Array mit Schlüsseln füllen, die die Namen der Spalten sind. Der Rest des Codes istmehr oder wenigerFNR == 1
unverä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