
Ich habe eine Datei wie diese:
OV2 OVI 1VI OV3 3VI
er 23 23 23 23 23
tr 24 24 24 24 24
Ich möchte die 1. Spalte zusammen mit allen Spalten drucken, deren Name enthält VI
(ich weiß vorher nicht, welche Spalten die Zeichenfolge enthalten werden). Im obigen Beispiel sollte die Ausgabe folgendermaßen aussehen:
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
Alle Spalten sollten durch Tabulatoren getrennt sein.
Antwort1
perl -lane '$,="\t";
$. == 1 and @A = grep $F[$_] =~ /VI/, 0..$#F;
print @F[0,@A];
' yourfile
Ergebnisse
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24
Arbeiten
- Extrahieren Sie aus der ersten Zeile
$. == 1
die Indizes der Felder, die die Zeichenfolge enthaltenVI
. - Ausgestattet mit dieser Liste von Indizes, die sich jetzt im Array befinden
@A
, schneiden wir einfach das 1. Feld + die im@A
Array aufgelisteten Felder aus dem@F
Array heraus. DasOFS=$,
wurde auf ein gesetztTAB
. YMMV.
awk
awk -v OFS="\t" '
NR==1{
for ( i=2; i<=NF; i++ )
if ( $i ~ /VI/ )
str = str OFS i
N = split(str, A, OFS)
}{
s = $1
for ( i=2; i<=N; i++ )
s = s OFS $(A[i])
$0 = s
}1
' yourfile
SED
sed -e '
# TAB->spc, multiple spc -> single spc, trim leading/trailing spc
y/ / /;s/[ ]\{2,\}/ /g;s/^[ ][ ]*//;s/[ ][ ]*$//
# only for first line, remove the first field and store remaining in hold area
1{
h
s/[ ]/\
/
s/.*\n//
x
}
# append hold area (which now has 2nd...last fields
# data of the first record) to the present line and
# place a marker at the end of the first field
G
s/[^ ][^ ]*[ ]/&\
/
# setup a do-while loop which progressively either keeps VI data or trims it
:loop
# 1 2 3
s/\(\n\)\([^ ][^ ]*\)[ ]\{0,1\}\(.*\n\)[^ ]*VI[^ ]*[ ]\{0,1\}/ \2\1\3/;tloop
s/\(\n\)[^ ][^ ]*[ ]\{0,1\}\(.*\n\)[^ ][^ ]*[ ]\{0,1\}/\1\2/
/\n\n$/!bloop
# loop ends when the two \ns collide at the end of line
# remove the two \ns and what remains is what you wanted
s///
' yourfile
Antwort2
awkLösung:
awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
{if($i~/VI/) a[i]; }}{r=$1; for(i in a) r=r OFS $i; print l}' file
Die Ausgabe:
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
FS="[\t ]+"
- EingabefeldtrennzeichenOFS="\t"
- AusgabefeldtrennzeichenNR==1
- zum ersten MalHeaderLinieif($i~/VI/) a[i]
- Erfassen der Feldnummer, wenn diese übereinstimmtVI
r=$1; for(i in a) r=r OFS $i; print r
- Durchlaufen der benötigten Feldnummern und Drucken der entsprechenden Werte
Wenn Sie auf eine Unterbrechung der Reihenfolge stoßen, verwenden Sie die folgende asorti()
Funktion (um das Array nach Indizes zu sortieren):
awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
{if($i~/VI/) a[i]; }}{r=$1; asorti(a,b); for(i in b) {r=r OFS $(b[i])} print r}' file
Antwort3
Python-Skriptlösung. Funktioniert auf der Grundlage der Analyse der ersten Zeile und dem Aufbau einer Spaltenliste. Die Spalten, die kein VI enthalten, werden auf „None“ gesetzt. Alle anderen Zeilen werden in Wörter aufgeteilt und zum Vergleich mit Spaltenlistenelementen paarweise verbunden. Wenn das entsprechende Spaltenelement „None“ ist, wird das Wort aus der aktuellen Zeile nicht gedruckt. Andernfalls werden Dinge gedruckt, die nicht „None“ sind.
#!/usr/bin/env python3
import sys
with open(sys.argv[1]) as fd:
indexes = []
for index,line in enumerate(fd):
if index == 0:
columns = line.strip().split()
for i,col in enumerate(columns):
if 'VI' in col or i == 0:
indexes.append(col)
else:
indexes.append(None)
for x in indexes:
if x:
print(x,end=" ")
print("")
continue
for j in zip(line.strip().split(),indexes):
if j[1]:
print(j[0],end=" ")
print("")
Hinweis: Ersetzen Sie end=" "
durch end="\t"
, um eine tabulatorgetrennte Ausgabe zu erhalten
Testlauf:
$ ./get_colums.py input.txt
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24