Transformaciones de texto

Cómo manipular el contenido de ficheros de texto


Cuando trabajamos desde una terminal y estamos revisando archivos de texto, como logs, registros o simplemente textos con datos, puede que nos interese hacer transformaciones en estos archivos, de modo que nos quedemos con fragmentos y partes específicas, descartando otras, y la herramienta grep no nos sea suficiente.

Para ello, vamos a ver una serie de comandos, que combinados, pueden convertirse en herramientas super potentes para transformar nuestros datos a nuestro gusto.

Primeras y últimas líneas

En primer lugar, tenemos los comandos head y tail, que nos permiten ver las primeras o las últimas líneas de un fichero, pudiendo seleccionar la cantidad.

Mediante el comando head, podemos indicar mediante un guión (-) el número de líneas que queremos filtrar, desde el principio de un fichero o contenido. Por ejemplo:

$ head -8 quijote.txt

Como puedes ver, nos hemos quedado sólo con las 8 primeras líneas del quijote.txt. Obviamente, esto también podemos hacerlo encadenando un comando:

$ ls -lh | head -5

Esto nos mostraría sólo las primeras 5 líneas de la salida del comando ls -lh.

De la misma forma, el comando tail nos muestra las últimas líneas de un fichero. Al igual que con head, tras el guión (-) indicamos el número de líneas que queremos leer.

$ tail -8 quijote.txt

Por defecto, si no indicamos número, nos muestra las 10 últimas líneas.

El comando tail tiene un parámetro muy interesante: -f. Este parámetro hace que el comando se ejecute, muestre las últimas líneas y se mantenga abierto y en espera. De esta forma, si se escribe en el fichero, se va mostrando en tiempo real:

$ tail -8 quijote.txt

Esto es muy útil para ver logs o registros de un servidor web o una aplicación similar:

$ cat /var/log/access.log | tail -f

Para salir del modo tail -f, simplemente pulsamos Ctrl+C.

Ten en cuenta que, conociendo los comandos head y tail, puedes combinarlos utilizando encadenamiento para ver el contenido de un fichero desde una línea concreta hasta otra. Por ejemplo:

$ head -20 quijote.txt | tail -5

Este comando muestra el contenido del fichero quijote.txt desde la línea 15 hasta la línea 20.

El comando wc

El comando wc significa word count (contar palabras), pero no sólo cuenta palabras, sino que puede hacer muchas cosas más. Por ejemplo, con el parámetro -l le indicamos al comando wc que queremos mostrar las líneas de un fichero o de una información de entrada:

$ wc -l quijote.txt
37453 quijote.txt

Esto es realmente útil cuando queremos contar líneas rápidamente y obtener el total. Además, también podemos indicar un comodín como *.txt en lugar de un fichero específico, o utilizar encadenamientos.

Además, también podemos contar otras cosas:

ParámetroDescripción
wc -lCuenta líneas.
wc -mCuenta letras (carácteres).
wc -wCuenta palabras.
wc -cCuenta bytes.

El comando sort

El comando sort nos permite ordenar el contenido de un fichero (o la información de entrada). Por ejemplo, imaginemos un fichero numbers.txt que contiene estas 10 líneas, donde cada una de ellas tiene un número:

30
15
25
100
25
75
15
25a
100
25A

Vamos a ordenarlo, utilizando el comando sort y encadenamiento.

Mediante el comando sort sin parámetros podemos ordenar alfabéticamente. Con números no tendría mucho snetido, pero con nombres o contenido alfabético si. Imaginemos el fichero doctors.txt:

$ cat doctors.txt
William Hartnell
Patrick Troughton
Jon Pertwee
Tom Baker
Peter Davison
Colin Baker
Sylvester McCoy
Paul McGann
Christopher Eccleston
David Tennant
Matt Smith
John Hurt
Peter Capaldi
Jodie Whittaker
Ncuti Gatwa

Ahora, vamos a encadenar con el comando sort, de modo que ordenemos alfabéticamente el contenido:

$ cat doctors.txt | sort
Christopher Eccleston
Colin Baker
David Tennant
Jodie Whittaker
John Hurt
Jon Pertwee
Matt Smith
Ncuti Gatwa
Patrick Troughton
Paul McGann
Peter Capaldi
Peter Davison
Sylvester McCoy
Tom Baker
William Hartnell

Observa que los nombres ahora aparecen en orden alfabético, ya que primero aparecen los nombres que empiezan por C y al final los nombres que empiezan por W.

Ahora, vamos a utilizar el fichero numbers.txt que mencionamos anteriormente, y utilizaremos el parámetro -n, que nos permitirá ordenar de forma numérica, lo que tiene sentido cuando las líneas empiezan por números. Observa el ejemplo:

$ cat numbers.txt | sort -n
15
15
25
25
25a
25A
30
75
100
100

En este caso, se ha ordenado de forma que los números más pequeños aparecen antes y los mayores después. En el caso de haber utilizado el sort sin el parámetro -n colocaría el 100 antes que el 15, simplemente porque empieza por 1 y lo está ordenando alfabéticamente.

Utilizando el parámetro -r podemos invertir el orden del ordenamiento, y utilizando el parámetro -R utilizar orden aleatorio. Observa los siguientes ejemplos:

$ cat numbers.txt | sort -nr
100
100
75
30
25A
25a
25
25
15
15

En este caso, hemos ordenado numéricamente y hemos invertido el orden, de modo que los números aparecen de mayor a menor. Esto también se podría realizar con el orden alfabético si omitimos el parámetro -n.

Por otro lado, si utilizamos el parámetro -R ordenaremos de forma aleatoria las líneas, sin embargo, mantendrá agrupados los elementos que tengan el mismo patrón:

$ cat numbers.txt | sort -R
15
15
25a
75
25
25
100
100
30
25A

Por otro lado, si lo que buscamos es desordenar líneas, o lo que es lo mismo, establecer un orden aleatorio completo, sin agrupaciones, podemos encadenar con el comando shuf (de shuffle):

$ cat numbers.txt | shuf
25A
15
75
25
30
100
25a
100
15
25

El comando uniq

Un comando muy interesante y útil es el comando uniq. Este comando nos permite eliminar líneas contiguas duplicadas.

Por ejemplo, vamos a seguir trabajando con el fichero numbers.txt anterior.

$ cat numbers.txt | sort | uniq
100
15
25
25a
25A
30
75

Observa que los números 25, 15 y 100, a pesar de estar duplicados, ahora no aparecen duplicados.

Por otro lado, algo que también es muy interesante, es que además de eliminar los duplicados, podemos indicarle que cuente las lineas duplicadas. Por ejemplo:

$ cat numbers.txt | sort -n | uniq -c
  2 15
  2 25
  1 25a
  1 25A
  1 30
  1 75
  2 100

Observa que antes de la línea, aparece un número. Este número indica el número de veces que ha encontrado esa línea. Por esa razón, los números 15, 25 y 100 tienen un 2 antes, mientras que el resto tiene un 1 (solo aparece una vez).

Luego, podríamos volver a encadenar nuevamente un sort -nr y ordenar las líneas por los resultados que más duplicados ha encontrado.

Transformar textos

Existen comandos muy útiles para realizar transformaciones a las líneas de texto de un archivo. Por ejemplo, los comandos cut o tr son bastante útiles para tareas de este tipo.

El comando cut nos permite recortar fragmentos o zonas de lineas de texto. En primer lugar, utilizamos el parámetro -d para establecer un delimitador, es decir, un caracter que actuará de separador. Se puede indicar entre comillas dobles ("), comillas simples (') o simplemente indicándolo pegado al -d.

Esto hará que si, por ejemplo, indicamos -d" " estemos estableciendo los espacios como separadores. De esta forma, si tenemos un archivo con nombres y apellidos como en doctors.txt, tendremos una columna con el nombre y una columna con el apellido.

Luego, con el parámetro -f podemos indicar las columnas que queremos obtener. Por ejemplo, con -f1 indicamos que queremos la primera columna (en este caso, los nombres):

$ cut -d" " -f1 doctors.txt
William
Patrick
Jon
Tom
Peter
Colin
Sylvester
Paul
Christopher
David
Matt
John
Peter
Jodie
Ncuti

Sin embargo, el parámetro -f es muy personalizable, y poder obtener una columna, varias de ellas o incluso rangos:

ParámetroDescripción
-f2Muestra el segundo campo.
-f1,3Muestra el primer y tercer campo.
-f1-3Muestra desde el primer al tercer campo.
-f-2Muestra desde el primer al segundo campo.
-f3-Muestra desde el tercer al último campo.

Existe un comando llamado tr (translate) mediante el cuál podemos traducir ciertos carácteres a otros. Su uso es bastante sencillo. Observa los siguientes ejemplos donde utilizamos el comando tr sobre un texto mostrado con echo:

$ echo "Hola a todos" | tr a i
Holi i todos

En este caso, traducimos todas las a por una i. Pero también podemos hacerlo con una serie de carácteres que corresponden a otra serie de carácteres:

$ echo "Hola a todos" | tr "ao" "iu"
Huli i tudus

Aquí, todas las a se convierten en i y todas las o se convierten en u. Si en la segunda parte sólo pusieramos un caracter, se convertirían todos a ese.

Luego, mediante el parámetro -d podemos simplemente eliminar los carácteres indicados:

$ echo "Hola a todos" | tr -d "o"
Hla a tds

Y de forma muy similar, -s (squeeze) permite unir todos los carácteres consecutivos que coincidan y simplificarlo en uno solo, algo que puede ser muy útil cuando tenemos comandos que devuelven muchos espacios y queremos simplificarlos.

$ echo "Hooooola a todos" | tr -s "o"
Hola a todos

Existe un comando muy interesante llamado choose. Con él podemos obtener textos como lo hacemos con el cut pero de una forma mucho más sencilla.

$ echo "Hola a todos amigos" | choose 3
todos

$ echo "Hola a todos amigos" | choose 2:4
todos amigos

$ echo "Hola a todos amigos" | choose 2 0
todos Hola

En la página de choose puedes echar un vistazo a varios ejemplos. Recuerda que este comando no viene por defecto, y necesitas tener Rust instalado e instalarlo mediante cargo install choose.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev