ENTENDIENDO LO QUE SON LOS ‘ONE LINERS’

Entre los administradores de sistemas Linux es común el término ‘one liners’, algo asi como ‘los de una línea’, y se refiere a un comando o mejor dicho a un conjunto de comandos que en una sola línea de la interface de comandos, combinados adecuadamente producirán un resultado útil y práctico. La unión de estos comandos generalmente se realiza a través del signo barra |, pipe en inglés.

Por ejemplo, si necesitas saber cuantos archivos hay en el directorio actual, el siguiente grupo de comandos lo hará:

ls | wc -l

Hay que recordar un simple principio cuando se usan pipes |, y es que el comando a la izquierda le ‘pasa’ el resultado de su ejecución al comando a la derecha. En este caso, la salida de ls se convierte en la entrada de wc que con la opción l contará las líneas resultantes. Una variante de esto mismo puede ser el siguiente

ls | cat -n

Con la opción n el comando cat numera las líneas de la salida previa. Creo que con estos ejemplos es suficiente para tener la idea de lo que se trata de hacer a través de un ‘one liner’. Veamos ahora unos ejemplos más elaborados.

Digamos que te interesa continuamente saber cuáles son los 5 procesos que consumen más ciclos del CPU:

ps -eo pcpu,user,pid,cmd | sort -r | head -5

Aqui, usas la opción o del comando ps que permite personalizar la salida del mismo, indicando las columnas que deseas sean mostradas. La opción e del mismo comando indica salida ‘extended’ es decir procesos de todos los usuarios (más sobre procesos en este artículo de LinuxTotal.com.mx). Toda esta primera salida, que puede ser bastante extensa es tomada por sort que a través de la opción r realiza un ordenamiento inverso en base a la primera columna, que es ‘pcpu’, que indicará precisamente el porcentaje de uso de cada proceso en el CPU. Y por último esta salida es enviada al comando head que muestra las primeras 5 líneas de la salida previa.

Si te gusto el comando o piensas usarlo de manera continua, te conviene entonces crear un alias del mismo, y colocarlo dentro de ‘.bashrc’ o archivo similar para que sea cargado el inicio de la sesión, asi solo tendrás que invocar el alias y no todo el comando.

alias p5="ps -eo pcpu,user,pid,cmd | sort -r | head -5"

Una situación común para administradores de servidores Linux con varias decenas o cientos de usuarios es la de obtener listas rápidas de los usuarios del sistema. Múltiples variantes de ‘one liners’ se pueden crear para estos casos, una muy simple puede ser la siguiente:

cat /etc/passwd | sort

Pero si solo necesitas el nombre de usuario (username), lo de arriba produce demasiada información, puedes arreglar aun más el comando con lo siguiente:

cat /etc/passwd | sort | cut -d":" -f1

Eso ya produce un resultado mucho mejor, ya que solo muestra los nombres de usuario. El comando cutpermite a través de la opción d indicar cual es el caracter que se utiliza como separador de campos, que en este caso es ‘:’, y con f1 se indica que extraiga el primer campo, que es precisamente el nombre de usuario. Entonces, cat /etc/passwd muestra todo el archivo de usuarios del sistema, sort lo ordena, y despuéscut extrae solo la primera columna.

Pero si observac con atención, realmente el resultado no es del todo útil, porque tendrás nombres de usuarios del sistema, es decir usernames como apache, bin, lp, etc. Solo se requiere en la lista nombres de usuarios de usuarios reales, es decir de seres humanos, asi que probemos de otro modo:

cat /etc/passwd | sort | gawk '$3 >= 500 {print $1 }' FS=":"

gawk evalua cada línea de la salida previa (cat /etc/passwd | sort), y si el tercer campo $3, que es el UID User Id de cada usuario, es mayor o igual a 500 (la mayoría de las distribuciones modernas de Linux comienzan numerando a los usuarios normales a partir de este número), entonces la acción se ejecuta, que esta indicada entre { } llaves, y esta acción es imprimir el primer campo $1. El separador de campor esta indicado a través de la opción FS (field separator).

Veamos otra situación donde tienes un directorio repleto de archivos php revuelto con archivos html y algunos otros archivos con diferentes extensiones. Todos los archivos php necesitas respaldarlos, puede ser el mismo nombre que ya tienen pero agregándole la extensión ‘.resp’ de respaldo al final. El siguiente ‘one liner’ deberá cumplir con el trabajo:

for f in *.php; do cp $f $f.resp; done

Un ciclo recorrerá todos los archivos en el directorio actual que terminen con ‘php’ (for f in *.php;), el nombre de cada archivo se almacenará en la variable $f, la siguiente parte, el interior del ciclo, hará una simple copia (cp) asi, ‘archivo.php’ será copiado a ‘archivo.php.resp’. En este ejemplo habrás notado que en vez de |, usé ; como separador de comandos, porque no quiero encadenarlos o entubarlos sino que uno se ejecute después del otro y eso se logra con ; como separador de comandos.

¿Que tal hacer copias masivas, a modo de respaldos?, bien, el siguiente comando es un clásico, hay varias versiones del mismo, pero mas o menos es algo como lo siguiente:

tar cf - . | (cd /usr/backups/; tar xfp -)

Copia (realmente produce un paquete comprimido) completa y recursivamente el directorio actual (tar cf - .), entonces el paquete es enviado al siguiente comando entubado por | ((cd /usr/backups/; tar xfp -)), los paréntesis crean un subshell en el que se cambia al directorio indicado y extrae x el contenido del paquete, todo el directorio y subdirectorios originales en una nueva ubicación. La opción p en el segundotar preserva la fecha, permisos, etc. de cada archivo. Después de completarse la copia, el prompt del shell regresa al directorio original.

Una variante del previo ‘one liner’ es cuando necesitas hacer lo mismo, pero en un servidor remoto, no en el mismo equipo como previamente se mostró:

tar cf - . | ssh sergio@servidor.remoto tar xfp - -C /usr/respaldos/sergio

En este caso, una sesión de ssh es establecida después de que el comando inicial tar hizo su trabajo, la opción C indica al segundo tar cambiar de directorio, que será ‘/usr/respaldos/sergio’ en el servidor remoto y ahí es donde la extracción se realizará completando el respaldo.

Procesamiento de texto es otro lugar común para los ‘one liners’, cosas asombrosas pueden realizarse con el conjunto y orden correcto de comandos. En el siguiente ejemplo, un reporte de correos entrantes pudiera lucir como lo que sigue:

$> cat correos_entrantes
2008-07-01 08:23:17 usuario1@ejemplo.com
2008-07-01 08:25:20 usuario2@someplace.com
2008-07-01 08:32:41 alguien@server.net
2008-07-01 08:35:03 spam no recibido, filtrado
2008-07-01 08:39:57 usuario1@ejemplo.com
...

Se te pide un reporte con lista ordenada alfabéticamente de los correos entrantes. Muchos correos se repiten a través del reporte original, y solo se necesita uno de cada uno. El siguiente ‘one liner’ lo resuelve completamente:

grep '@' incoming_email | gawk '{print $3}' | sort | uniq

La salida o resultado es el siguiente:

alguien@server.net
usuario1@ejemplo.com
usuario2@someplace.com

grep filtra las líneas que contienen un caracter ‘@’. A continuación gawk extrae del resultado el tercer campo que es la dirección de correo electrónico, después esta lista de correos es ordenada alfabéticamente con sort. Esto es necesario para que agrupe los correos similares, ya que el último comando uniq sin opción alguna omite las líneas repetidas de la lista ordenada previamente. El resultado final es una lista de correos pero solo uno de cada uno, ya que no tiene caso mostrar las repeticiones.

Estoy consciente de que puede haber mejores y más simples variaciones de los comandos mostrados en este artículo. La idea es introducir a los principantes o incluso a usuarios ya más acostumbrados a la línea de comandos pero que desean mejorar sus habilidades en la formación de comandos elaborados. Si tu eres un administrador de sistemas es una buena práctica, crear o modificar a partir de otros, tus propios ‘one liners’, clasificarlos y tenerlos a la mano para cuando los necesites, nunca se sabe. Por ejemplo, en el último ejemplo, digamos que necesitas saber cuantos correos distintos hay en el resultado final, a lo que ya tienes solo necesitas agregar wc -l para obtener el resultado.

Recuerda siempre el espíritu detrás de Linux y del movimiento Open Source, “compartir”, asi que si tienes un buen ‘one liner’ por ahí deja que todos nos beneficiemos de el, compártelo.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s