Tengo un archivo de texto:
1 Q0 1657 1 19.6117 Exp
1 Q0 1410 2 18.8302 Exp
2 Q0 3078 1 18.6695 Exp
2 Q0 2434 2 14.0508 Exp
2 Q0 3129 3 13.5495 Exp
Quiero tomar la segunda y cuarta palabra de cada línea como esta:
1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495
Estoy usando este código:
nol=$(cat "/path/of/my/text" | wc -l)
x=1
while [ $x -le "$nol" ]
do
line=($(sed -n "$x"p /path/of/my/text)
echo ""${line[1]}" "${line[3]}"" >> out.txt
x=$(( $x + 1 ))
done
Funciona, pero es muy complicado y lleva mucho tiempo procesar archivos de texto largos.
¿Existe una forma más sencilla de hacer esto?
Respuestas:
iirc:
cat filename.txt | awk '{ print $2 $4 }'
o, como se menciona en los comentarios:
awk '{ print $2 $4 }' filename.txt
fuente
awk '{print $2,$4}' filename.txt
es mejor (sin tubería, solo se llama un programa)cat
en mis scripts bash en lugar de especificar un nombre de archivo, porque la sobrecarga es mínima y porque la sintaxiscat ... | ... > ...
muestra muy bien cuál es la entrada y hacia dónde va la salida. Sin embargo, tiene razón, en realidad no es necesario aquí.< input awk '{ print $2 $4 }' > output
con ese propósito.Puedes usar el
cut
comando:cut -d' ' -f3,5 < datafile.txt
huellas dactilares
los
-d' '
- es decir, utilizarspace
como delimitador-f3,5
- tomar e imprimir la tercera y quinta columnaEl
cut
es mucho más rápido de archivos de gran tamaño como una solución pura cáscara. Si su archivo está delimitado con varios espacios en blanco, puede eliminarlos primero, como:sed 's/[\t ][\t ]*/ /g' < datafile.txt | cut -d' ' -f3,5
donde el (gnu) sed reemplazará cualquier carácter
tab
ospace
con un solospace
.Para una variante, aquí también hay una solución de Perl:
perl -lanE 'say "$F[2] $F[4]"' < datafile.txt
fuente
En aras de la exhaustividad:
while read _ _ one _ two _; do echo "$one $two" done < file.txt
En lugar de
_
una variable arbitraria (comojunk
) también se puede utilizar. El punto es solo extraer las columnas.Manifestación:
$ while read _ _ one _ two _; do echo "$one $two"; done < /tmp/file.txt 1657 19.6117 1410 18.8302 3078 18.6695 2434 14.0508 3129 13.5495
fuente
Una variante más simple:
$ while read line do set $line # assigns words in line to positional parameters echo "$3 $5" done < file
fuente
Si su archivo contiene n líneas, entonces su secuencia de comandos debe leer el archivo n veces; por lo que si duplica la longitud del archivo, cuadriplica la cantidad de trabajo que hace su script, y casi todo ese trabajo simplemente se tira a la basura, ya que todo lo que desea hacer es recorrer las líneas en orden.
En cambio, la mejor manera de recorrer las líneas de un archivo es usar un
while
bucle, con el comando de condiciónread
integrado:while IFS= read -r line ; do # $line is a single line of the file, as a single string : ... commands that use $line ... done < input_file.txt
En su caso, dado que desea dividir la línea en una matriz, y la función
read
incorporada en realidad tiene un soporte especial para completar una variable de matriz, que es lo que desea, puede escribir:while read -r -a line ; do echo ""${line[1]}" "${line[3]}"" >> out.txt done < /path/of/my/text
o mejor aún:
while read -r -a line ; do echo "${line[1]} ${line[3]}" done < /path/of/my/text > out.txt
Sin embargo, para lo que está haciendo, puede usar la
cut
utilidad:cut -d' ' -f2,4 < /path/of/my/text > out.txt
(o
awk
, como sugiere Tom van der Woerdt, operl
, o inclusosed
).fuente
read
máscut
porque es robusto frente a múltiples espacios entre los campos y que no necesita la magia matriz:while read word1 word2 word3 word4 rest; do doSomethingWith $word2 $word4; done
Si está utilizando datos estructurados, esto tiene el beneficio adicional de no invocar un proceso de shell adicional para ejecutar
tr
y /cut
o algo. ...(Por supuesto, querrá protegerse contra las malas entradas con condicionales y alternativas sensatas).
... while read line ; do lineCols=( $line ) ; echo "${lineCols[0]}" echo "${lineCols[1]}" done < $myFQFileToRead ; ...
fuente