La linea de comandos de Unix

La linea de comandos de Unix

Introducción

En informática todo tiene los días contados. En cuestión de un par de años lo que era novedoso se empieza a ver como cotidiano y lo que era cotidiano se empieza a considerar desfasado.

El párrafo anterior sería cierto si no hubiera honrosas excepciones como el editor de textos Emacs, que vio la luz en 1976. Otra excepción es una de las mejores herramientas para programadores y administradores de sistemas: La línea de comandos de Unix, la cual lleva con nosotros desde 1970. Aquí hablaremos de esta última.

En este post se usa Unix en sentido amplio, no estricto. Incluyendo en este conjunto a Linux y Mac OS X. UNIX, en mayúsculas, es una marca de Open Group y ellos deciden que es UNIX y que no. Linux parece que no y algunas versiones de Mac OS X parece que tampoco, mientras que otras sí.

La interfaz de línea de comandos o “consola” es la antítesis de la interfaz gráfica. La primera es tosca, fondo negro, letras y teclado. La segunda es vistosa, gráficos coloridos, ventanas y ratón.

Varias consolas abiertas

Para quién es la consola

Si no eres administrador de sistemas o programador puede que el tiempo y esfuerzo invertido en aprender a usar la línea de comandos no se vea compensado con los beneficios que obtengas de ello.

Unix y los ficheros de texto

Dentro de la filosofía de Unix encontramos los siguientes conceptos:

  • Un programa realiza una única tarea.
  • La salida de un programa puede ser la entrada de otro.
  • Los programas tendrán como entrada y salida texto.
  • Casi todo en Unix es un fichero (dispositivos, IPCs, datos del kernel…)
  • Los archivos se ordenan de manera jerárquica en directorios.

Teniendo en cuenta los puntos anteriores: programas sencillos y comunicación entre ellos mediante flujos de texto, es lógico que surjan dos clases de programas auxiliares:

  • Programas para manejar ficheros y directorios: ls, rm, cp, mv, mkdir, find, file, cat, tail…
  • Programas para manejar texto: grep, awk, sort, uniq, xargs…

Explosión combinatoria

Mezclando los distintos programas de la linea de comandos se obtiene un sin fin de opciones que permiten resolver muchas clases de problemas.

Para conseguir tanta variedad en entornos de interfaz gráfica habría que:

  1. Llenar los programas de opciones o
  2. tener infinidad de programas

La primera opción hace programas difíciles de usar y confusos. Mientras que la segunda implica tener que recordar el nombre del programa necesario para cada tarea, además del coste de desarrollar todos los programas.

Ejemplos del uso de la línea de comandos

A continuación muestro varios ejemplos, basados en usos realistas, para ilustrar un poco mejor por qué la línea de comandos es una gran herramienta.

Si quieres saber las opciones de cada programa lo mejor es usar la ayuda de la consola, suele ser más rápido que google.

man uniq

Escuchar canciones aleatoriamente

Queremos escuchar una canción al azar de nuestra colección de música.

Desde el directorio donde tengamos la colección de música ejecutamos:

mplayer "`find . -name "*.mp3" | sort -R | head -1`"

Breve explicación del cometido de cada programa en este caso particular:

  • mplayer: Reproduce la canción.
  • find: Encuentra todos los ficheros que terminen en mp3.
  • sort: Ordena aleatoriamente.
  • head: Muestra una única línea.

Si lo que queremos es escuchar canciones aleatorias continuamente:

while true; do mplayer "`find . -name "*.mp3" | sort -R | head -1`"; done
  • while: Ejecuta el programa continuamente.

Es obvio que esto podría parecer poco útil porque los programas comunes de música tienen modo de reproducción aleatorio. Pero este ejemplo da una idea del potencial de la línea de comandos.

Monitorizar temperatura de la CPU

¿Estamos preocupados por la temperatura de nuestra CPU? Pues vamos a monitorizarla en una terminal.

Afortunadamente en Unix todo es un fichero y los datos de los sensores de temperatura también están en uno.

cat `find /sys/devices/virtual -name "temp"`

Descripción:

  • cat: Muestra el contenido de un fichero.
  • find: Busca ficheros con nombre temp.

Ahora, si queremos tenerlo siempre presente: Reducimos la consola, la colocamos en una esquina de nuestro escritorio que no moleste mucho y ejecutamos:

while true; do clear; cat `find /sys/devices/virtual -name "temp"`; sleep 4; done
  • while: Ejecuta el programa continuamente.
  • clear: Borra la pantalla.
  • sleep: Espera 4 segundos. Para que el ordenador no gaste recursos a lo tonto.

Qué programas uso más

Hablando de la línea de comandos, ¿Cúales son los programas que más uso?

dani@osc:~$ history | awk '{print $2}' | sort | uniq -c | sort -nr | head -15
    263 ls
    149 cd
    100 git
     65 cat
     25 python
     25 mplayer
     24 ssh
     23 rm
     23 find
     22 tar
     21 emacs
     17 e
     15 ipython
     13 ping
     13 nc
  • history: Muestra los 500 últimos comandos usados (El número es configurable).
  • awk: Muestra la segunda columna usando como separación los espacios.
  • sort: Ordena las filas en orden alfabético.
  • uniq: Agrupa las líneas iguales y cuenta las veces que aparecen.
  • sort: Ordena las filas en orden numérico y reverso.
  • head: muestra los 15 primeros comandos.

Análisis de datos

Además de los ficheros de texto propiamente dichos hay otro tipo de formatos que bien son texto, como el código fuente de un programa y algunos tipos de logs, o bien se pueden representar como texto de manera natural como HTML, XML y JSON.

Para ciertos tipos de análisis se pueden usar las herramientas de Unix con la precaución de saber lo que se hace. Es decir, no podemos olvidarnos de los parsers para analizar documentos estructurados pero si que podemos usar estas herramientas para, de manera instantánea, obtener un resultado.

Hay que advertir que cuando analizamos este tipo de archivos como texto tenemos que tener en cuenta saltos de línea y espacios en blanco. De forma que si el formato no es conocido ni predecible es mejor no usar estos métodos. Tampoco se deben usar estos métodos para hacer aplicaciones reutilizables.

Ahora muestro algunos ejemplos donde podrían ser útiles estos hacks. Estos ejemplos están sacados de un día de trabajo analizando ficheros:

Los JSON fueron creados por mí con el contenido ordenado en lineas y bien justificado para poder usarlo como flujos de texto.

Tenemos dos tipos de ficheros de error: file_1.error y file_2.RAW.error dentro del directorio PDFS en distintos subdirectorios. Queremos coger una muestra aleatoria de 10 ficheros del tipo file_1.error.

find PDFS/ -name "*.error"|grep -v RAW|sort -R|tail -n 10
  • find: Busca los ficheros que terminan en .error.
  • grep: Descarta los que contienen RAW.
  • sort: Los ordena aleatoriamente.
  • tail: Nos muestra 10.

Borrar todos los ficheros filest.txt y files.txt a partir de un directorio:

find . -name "*files.txt*" -exec rm '{}' \;
  • find: Busca los ficheros que empiezan por files.txt y los borra con rm.

Queremos localizar los ficheros del directorio actual cuyo nombre se repite sólo dos veces (sin importar la extensión). Esto se usa para encontrar los ficheros que funcionaron en el primer procesado y fallaron en el segundo.

ls | awk -F. '{print $1}' | sort | uniq -c | egrep "\s2"
  • ls: Lista los ficheros.
  • awk: Nos devuelve la primera columna usando como separador un punto.
  • sort: Ordena los ficheros.
  • uniq: Muestra las lineas que se repiten precedidas del número de veces.
  • egrep: Se queda por las líneas que empiezan con espacios y un 2.

Supongamos que un fichero de error con formato JSON y con un salto de línea después de cada propiedad. Por ejemplo:

[
  {
    "label": "Nombramientos",
    "value": "Un valor aquí,
    "data": "27-2-22",
    "num": "123",
    "tipo_error": "333",
    "texto": "Un error comun"
  },
  {
    ...
  }
   ...
]

Queremos buscar etiquetas (label) distintas en un archivo de este tipo.

cat BORME-A-2009-10-08.error | grep label | sort | uniq

Ahora para una etiqueta dada, por ejemplo “Nombramientos”, queremos que se listen todos los valores (“value”):

cat BORME-A-2009-10-08.error | grep -n1 Nombramientos | grep value | awk -F\: '{print $2}' | tr '"' " " | sort | uniq

Ahora queremos unir todos los errores de tipo “file_1.error” en un único fichero grande:

find PDFS/ -name *.error | grep -v RAW|xargs cat > ERRORS.json

De la unión anterior hay un error que nos da un JSON inválido: ][ pues finaliza un array y empieza el siguiente. Lo que queremos es que sea todo un único array, para esto:

sed -i -e 's/\]\[/,/' ERRORS.json

Por último, si queremos obtener los 8 primeros carácteres del contenido de la propiedad “value” y mostrar los más habituales:

cat ERRORS.json | grep value | awk -F\" '{print $4}' | cut -c1-8|sort |uniq -c |sort -n

Todos estos problemas los podría resolver un programador que no conociera la línea de comandos pero le llevaría más tiempo, teniendo que escribir un programa para cada caso.

Otros usos de la línea de comandos

Sólo mencionar que la línea de comandos es de gran utilidad para analizar redes de ordenadores gracias a herramientas como nc, tcpdump, ping, netstat

Del mismo modo para administrar sistemas Unix contamos con: top, ps, free, du, strace

Cualquiera de los dos grupos de herramientas anteriores dan para escribir varios libros e igual en otra ocasión pongo ejemplos del uso de éstas.

¿Qué pasa con Windows?

Lo cierto es que Windows ha estado bastante atrás en lo que se refiere a línea de comandos. En 2006 crearon PowerShell para subsanar este error y por referencias parece que no está mal…

Pero si eres un adicto sin remedio a la consola de Unix y te ves obligado a usar Windows quizás puedas ir tirando con las adaptaciones de ésta a Windows:

  • Cygwin
  • MinGW

Referencias

La linea de comandos de Unix

Deja un comentario