bash - ejemplos - django
BASH: Resumiendo información de varios campos en un campo único usando instrucciones Loop y If (4)
Con GNU awk para que el 3er arg coincida ():
$ awk ''{match($0,/((/S+/s+){6})(.*)/,a); c=gsub(2,2,a[3]); print a[1] (c>1?2:1), (c>0?2:1)}'' file
A1 A1 0 0 2 1 1 2
A2 A2 0 0 2 1 1 1
A3 A3 0 0 2 2 2 2
A5 A5 0 0 2 2 1 2
Con otras awks reemplazarías /S//s
con [^[:space:]]/[[:space:]]
y substr()
lugar de a[]
.
Tengo el siguiente archivo separado por tabuladores:
A1 A1 0 0 2 1 1 1 1 1 1 1 2 1 1 1
A2 A2 0 0 2 1 1 1 1 1 1 1 1 1 1 1
A3 A3 0 0 2 2 1 1 2 2 1 1 1 1 1 1
A5 A5 0 0 2 2 1 1 1 1 1 1 1 2 1 1
La idea es resumir la información entre la columna 7 (incluida) y el final en una nueva columna que se agrega al final del archivo.
Para hacerlo, estas son las reglas:
Si el número total de "2" s en la fila (entre la columna 7 y el final) es 0 : agregue "1 1" a la última columna nueva
Si el número total de "2" s en la fila (entre la columna 7 y el final) es 1 : agregue "1 2" a la última columna nueva
Si el número total de "2" s en la fila (entre la columna 7 y el final) es 2 o más : agregue "2 2" a la última columna nueva
Empecé a extraer las columnas en las que quiero trabajar usando el comando:
awk ''{for (i = 7; i <= NF; i ++) printf $ i ""; print ""} ''myfile.ped> tmp_myfile.txt
Luego cuento el número de ocurrencias en cada fila usando:
sed ''s / [^ 2] // g'' tmp_myfile.txtt | awk ''{print NR, length}''> tmp_occurences.txt
Qué salidas:
1 1
2 0
3 2
4 1
Entonces, mi idea era escribir un bucle for que recorriera las líneas para agregar la nueva columna de resumen. Estaba pensando en este tipo de estructura , en base a lo que encontré aquí: http://www.thegeekstuff.com/2010/06/bash-if-statement-examples :
while read line ;
do
set $line
If ["$2"==0]
then
$3=="1 1"
elif ["$2"==1 ]
then
$3=="1 2”
elif ["$2">=2 ]
then
$3==“2 2”
else
print ["error"]
fi
done < tmp_occurences.txt
Pero estoy atrapado aquí. ¿Tengo que crear la nueva columna antes de comenzar el ciclo? ¿Voy en la dirección correcta?
Idealmente, el resultado final (después de fusionar las primeras 6 columnas del archivo inicial y la columna de resumen) sería:
A1 A1 0 0 2 1 1 2
A2 A2 0 0 2 1 1 1
A3 A3 0 0 2 2 2 2
A5 A5 0 0 2 2 1 2
¡Gracias por tu ayuda!
Podemos mantener el formato usando gensub()
y capturando grupos: gensub()
los 6 primeros campos y reemplazamos con ellos + los valores calculados:
awk ''{for (i=7; i<=NF; i++) {
if ($i==2)
twos+=1 # count number of 2''s from 7th to last field
}
f7=1; f8=0 # set 7th and 8th fields''s default value
if (twos)
f8=2 # set 8th = 2 if sum is > 0
if (twos>1)
f7=2 # set 7th = 2 if sum is > 1
$0=gensub(/^((/S+/s*){6}).*/,"//1 " f7 FS f8, 1) # perform the replacement
twos=0 # reset counter
}1'' file
Como un trazador de líneas:
$ awk ''{for (i=7; i<=NF; i++) {if ($i==2) twos+=1} f7=1; f8=0; if (twos) f8=2; if (twos>1) f7=2; $0=gensub(/^((/S+/s*){6}).*/,"//1 " f7 FS f8,1); twos=0}1'' a
A1 A1 0 0 2 1 1 2
A2 A2 0 0 2 1 1 0
A3 A3 0 0 2 2 2 2
A5 A5 0 0 2 2 1 2
Usando gnu-awk puedes hacer:
awk -v OFS=''/t'' ''{
c=0;
for (i=7; i<=NF; i++)
if ($i==2)
c++
if (c==0)
s="1 1"
else if (c==1)
s="1 2"
else
s="2 2"
NF=6
print $0, s
}'' file
A1 A1 0 0 2 1 1 2
A2 A2 0 0 2 1 1 1
A3 A3 0 0 2 2 2 2
A5 A5 0 0 2 2 1 2
PD: si no usas gnu-awk puedes usar:
awk -v OFS=''/t'' ''{c=0; for (i=7; i<=NF; i++) {if ($i==2) c++; $i=""} if (c==0) s="1 1"; else if (c==1) s="1 2"; else s="2 2"; NF=6; print $0, s}'' file
$ cat > test.awk
{
for(i=1;i<=NF;i++) { # for every field
if(i<7)
printf "%s%s", $i,OFS # only output the first 6
else a[$i]++ # count the values of the of the fields
}
print (a[2]>1?"2 2":(a[2]==1?"1 2":"1 1")) # output logic
delete a # reset a for next record
}
$ awk -f test.awk test
A1 A1 0 0 2 1 1 2
A2 A2 0 0 2 1 1 1
A3 A3 0 0 2 2 2 2
A5 A5 0 0 2 2 1 2
Tomando algunas ideas de la solución de @ anubhava arriba:
$ cat > another.awk
{
for(i=7;i<=NF;i++)
a[$i]++ # count 2s
NF=6 # truncate $0
print $0 OFS (a[2]<2?"1 "(a[2]?"2":"1"):"2 2") # print $0 AND 1 AND 1 OR 2 OR 2 AND 2
delete a # reset a for next record
}