
Tengo un archivo como este:
OV2 OVI 1VI OV3 3VI
er 23 23 23 23 23
tr 24 24 24 24 24
Quiero imprimir la primera columna junto con las columnas cuyo nombre contenga VI
(no sé qué columnas contendrán la cadena de antemano). En el ejemplo anterior, el resultado debería ser así:
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
todas las columnas deben estar delimitadas por tabulaciones.
Respuesta1
perl -lane '$,="\t";
$. == 1 and @A = grep $F[$_] =~ /VI/, 0..$#F;
print @F[0,@A];
' yourfile
Resultados
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24
Laboral
- Desde la primera línea,
$. == 1
extrae los índices de los campos que contienen la cadenaVI
. - Armados con esta lista de índices ahora en matriz
@A
, simplemente seguimos adelante y cortamos el primer campo + los campos enumerados en la@A
matriz de la@F
matriz. SeOFS=$,
ha establecido enTAB
. 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
Respuesta2
awksolución:
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
La salida:
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
FS="[\t ]+"
- separador de campo de entradaOFS="\t"
- separador de campo de salidaNR==1
- Por el primeroencabezamientolíneaif($i~/VI/) a[i]
- capturar el número de campo si coincideVI
r=$1; for(i in a) r=r OFS $i; print r
- iterar a través de los números de campo necesarios e imprimir sus valores respectivos
Si encuentra una ruptura de orden, utilice la siguiente asorti()
función (para ordenar la matriz por índices):
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
Respuesta3
Solución de secuencia de comandos Python. Opera basándose en el análisis de la primera línea y la creación de una lista de columnas. Aquellas columnas que no tienen VI se establecen en Ninguna. Todas las demás líneas se dividen en palabras y se unen en pares con elementos de la lista de columnas para comparar. Si el elemento de la columna correspondiente es Ninguno, esa palabra de la línea actual no se imprimirá. De lo contrario, se imprimen los elementos que no son Ninguno.
#!/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("")
Nota: reemplace end=" "
con end="\t"
para tener una salida delimitada por tabulaciones
Prueba de funcionamiento:
$ ./get_colums.py input.txt
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24