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ámetro | Descripción |
---|---|
wc -l | Cuenta líneas. |
wc -m | Cuenta letras (carácteres). |
wc -w | Cuenta palabras. |
wc -c | Cuenta 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ámetro | Descripción |
---|---|
-f2 | Muestra el segundo campo. |
-f1,3 | Muestra el primer y tercer campo. |
-f1-3 | Muestra desde el primer al tercer campo. |
-f-2 | Muestra 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
.