Tag: Script

Marcando estilo en tu Shell de Linux

En esta entrada os voy a explicar cómo personalizar vuestra Shell de Linux, pero antes de nada me gustaría aclarar ciertos conceptos que suelen confundirse y que son los siguientes:

  • Terminal = tty = Entorno de entrada y salida de texto
  • Console = Terminal físico
  • Shell = Intérprete de línea de comandos

Hablando en tiempos pretéritos, la forma de interactuar con computadoras Unix era mediante dispositivos teleprinter parecidos a máquinas de escribir, algunas veces llamados teletypewriter o "tty".

teletypewriter

El nombre de terminal viene del punto de vista de la electrónica y el nombre consola viene del punto de vista del mueble. En sistemas tipo Unix, tty es el tipo de fichero particular que implementa un número de comandos adicionales (ioctls) más allá de lectura y escritura. Terminal es asumido como un sinónimo de tty y algunas ttys son proveídas por el kernel del sistema operativo a favor de un dispositivo de hardware (como el teclado, modem o puertos seriales). Otras ttys, llamadas también pseudo ttys, son proveídas por programas llamados emuladores de terminal, como son Xterm, Screen, SSH...

Una consola generalmente es un terminal físicamente hablando, que hace referencia al primer terminal conectado a la compuradora. En algunos sistemas como Linux y FreeBSD, la consola dispone de múltiples ttys que pueden ser seleccionados mediante la combinación de teclas:

CTRL+ALT+[F1 ... F12]

Siendo cada uno de los Fx desde F1 a F12 los distintos tty disponibles en el sistema.

Un shell es la interfaz principal que los usuarios ven cuando inician sesión, y cuyo propósito es iniciar otros programas. En sistemas Unix, shell hace alusión a la línea de comandos, cuya finalidad es recibir nombres de aplicaciones y los ficheros sobre los cuales actúa la misma, al presionar la tecla "enter".

Probablemente la shell más popular para Linux sea Bash, basado en la sintaxis de Bourne Shell, con el que se pueden realizar programas usando instrucciones Bash de cierta complejidad, con una estructura muy parecida a otros lenguajes de alto nivel.

Aclarados los conceptos base, vamos a proceder a dar un estilo propio al inicio de sesión de nuestra shell de Linux. La forma más sencilla de hacerlo es personalizando el fichero "/etc/motd" (Message Of The Day). Para ello ejecutamos el siguiente comando:

sudo nano motd

Se nos abrirá o creara el fichero con permisos de usuario. Dentro deberemos poner en texto plano lo que queramos que aparezca, guardar haciendo CTRL+O y salir con CTRL+X. Si andas falto de ideas puedes entrar a este generador de texto ASCII:

http://patorjk.com/software/taag

O a esta galería de imágenes ASCII:

http://www.chris.com/ascii/joan/www.geocities.com/SoHo/7373/index.html

Cuando guardes el fichero, prueba cómo ha quedado abriendo otro terminal y ejecutando el siguiente, le cual abre una sesión ssh de tu usuario contra tu propio equipo:

ssh 127.0.0.1

Pedirá la contraseña de usuario (la introduces) y verás el mensaje. Si no aparece, prueba a salir de la sesión ssh con "exit" y prueba a ejecutar el comando anterior de nuevo. Deberías entonces poder ver tu mensaje.

custom-motd

El MOTD de mi ejemplo podéis encontrarlo en:

https://gist.github.com/RDCH106/876cdb98e7d1b0f3ef22040213a48c40

Si lo que quieres es un mensaje del día más elaborado que no consista en hacer "print" de un texto plano, entramos en "/etc/update-motd.d" y listamos los ficheros con "ls":

update-motd

Se trata de una serie de scripts Bash que poseen una sintaxis especial en el nombre del fichero. Los números que preceden al nombre del fichero, indican el orden en que se ejecutan cuando se inicia una sesión, siendo los números menores los que se ejecutan antes. Estos ficheros a diferencia del "motd" contienen comandos que son ejecutados por el super-usuario "root" y se trata por tanto de ficheros interpretados.

Vamos a crear uno con nombre "20-stats" en el que mostraremos algunas estadísticas del sistema:

sudo nano 20-stats

Y copiamos el siguiente código:

#!/bin/bash

function color (){
  echo "\e[$1m$2\e[0m"
}

function extend (){
  local str="$1"
  let spaces=60-${#1}
  while [ $spaces -gt 0 ]; do
    str="$str "
    let spaces=spaces-1
  done
  echo "$str"
}

function sec2time (){
  local input=$1
  
  if [ $input -lt 60 ]; then
    echo "$input seconds"
  else
    ((days=input/86400))
    ((input=input%86400))
    ((hours=input/3600))
    ((input=input%3600))
    ((mins=input/60))
    
    local daysPlural="s"
    local hoursPlural="s"
    local minsPlural="s"
    
    if [ $days -eq 1 ]; then
      daysPlural=""
    fi
    
    if [ $hours -eq 1 ]; then
      hoursPlural=""
    fi
    
    if [ $mins -eq 1 ]; then
      minsPlural=""
    fi
    
    echo "$days day$daysPlural, $hours hour$hoursPlural, $mins minute$minsPlural"
  fi
}

borderColor=35
headerLeafColor=32
headerRaspberryColor=31
greetingsColor=36
statsLabelColor=33

borderLine="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
borderTopLine=$(color $borderColor "┏$borderLine┓")
borderBottomLine=$(color $borderColor "┗$borderLine┛")
borderBar=$(color $borderColor "┃")
borderEmptyLine="$borderBar                                                                              $borderBar"

header="$borderTopLine"

uptime="$(sec2time $(cut -d "." -f 1 /proc/uptime))"
uptime="$uptime ($(date -d "@"$(grep btime /proc/stat | cut -d " " -f 2) +"%d-%m-%Y %H:%M:%S"))"

label1="$(extend "$uptime")"
label1="$borderBar  $(color $statsLabelColor "Uptime........:") $label1$borderBar"

label2="$(extend "$(free -m | awk 'NR==2 { printf "Total: %sMB, Used: %sMB, Free: %sMB",$2,$3,$4; }')")"
label2="$borderBar  $(color $statsLabelColor "Memory........:") $label2$borderBar"

label3="$(extend "$(df -h ~ | awk 'NR==2 { printf "Total: %sB, Used: %sB, Free: %sB",$2,$3,$4; }')")"
label3="$borderBar  $(color $statsLabelColor "Home space....:") $label3$borderBar"

stats="$label1\n$label2\n$label3"

# Print motd
echo -e "$header\n$borderEmptyLine\n$stats\n$borderEmptyLine\n$borderBottomLine" 

Guarda haciendo CTRL+O y salir con CTRL+X.

Además vamos a añadir otro script más para personalizar el inicio de sesión del perfil, que lo haremos en "/etc/profile.d" . La razón de hacerlo en profile es debido a que los mensajes MOTD se ejecutan por el root y por ejemplo si hacemos un "whoami" nos devolverá siempre root. Para ello creamos un script "wellcome.sh" que nos saludará y mostrará la fecha y hora:

sudo nano wellcome.sh

Y copiamos el siguiente código:

#!/bin/bash

function color (){
  echo "\e[$1m$2\e[0m"
}

function extend (){
  local str="$1"
  let spaces=60-${#1}
  while [ $spaces -gt 0 ]; do
    str="$str "
    let spaces=spaces-1
  done
  echo "$str"
}

function center (){
  local str="$1"
  let spacesLeft=(78-${#1})/2
  let spacesRight=78-spacesLeft-${#1}
  while [ $spacesLeft -gt 0 ]; do
    str=" $str"
    let spacesLeft=spacesLeft-1
  done
  
  while [ $spacesRight -gt 0 ]; do
    str="$str "
    let spacesRight=spacesRight-1
  done
  
  echo "$str"
}

borderColor=35
headerLeafColor=32
headerRaspberryColor=31
greetingsColor=36
statsLabelColor=33

borderLine="━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
borderTopLine=$(color $borderColor "┏$borderLine┓")
borderBottomLine=$(color $borderColor "┗$borderLine┛")
borderBar=$(color $borderColor "┃")
borderEmptyLine="$borderBar                                                                              $borderBar"

me=$(whoami)

header="$borderTopLine"

# Greetings
greetings="$borderBar$(color $greetingsColor "$(center "Welcome back, $me!")")$borderBar\n"
greetings="$greetings$borderBar$(color $greetingsColor "$(center "$(date +"%A, %d %B %Y, %T")")")$borderBar"

# Print motd
echo -e "$header\n$borderEmptyLine\n$greetings\n$borderEmptyLine\n$borderBottomLine" 

Guarda haciendo CTRL+O y salir con CTRL+X.

Abrimos una sesión ssh de tu usuario contra tu propio equipo, como ya hemos hecho anteriormente, y veremos un inicio de sesión como el siguiente, pero con los datos de tu sesión y equipo.

custom-motd_2

La finalidad de estos MOTD y scripts de perfil, pueden servir para la generación de mensajes informativos concretos para los usuarios, la generación de paneles informativos del sistema para administradores o simplemente para personalizar/corporativizar un sistema Linux.

img_20160414_174706.jpg

Espero que este artículo os haya servido para aprender a explotar estas características tan útiles del inicio de sesión de Linux.

 

Breve Introducción a las Expresiones Regulares

Una de las herramientas más potentes y a la vez más avanzadas que puede tener cualquier persona que "flirtee" con código y tratamiento de texto, son las expresiones regulares. Una aplicación directa de las expresiones regulares es la detección de patrones dentro de textos o la validación de los mismo de acuerdo a un patrón.

Dicho más formalmente, las expresiones regulares son un lenguaje para la descripción de lenguajes. Una expresión regular define un lenguaje. Por ejemplo, la expresión regular /[a-z]+/ define el lenguaje formado por las cadenas que consisten en repeticiones de una o mas letras minúsculas.

En el ejemplo la expresión sólo nos encontraría aquellas palabras que tuviesen todas las letras en minúsculas. En este conjunto por consiguiente se excluirían todos los nombres propios, las primeras palabra tras un punto por ir escribirse en mayúsculas o incluso aquellas palabras que van todas sus letras en mayúsculas. Para ello basta incluir en la expresión anterior el conjunto de la mayúsculas, pudiendo aparecer ninguna mayúscula o n mayúsculas del conjunto de las letras mayúsculas. La expresión quedaría tal que así /[A-Z]*[a-z]+/. A continuación se adjuntan un par de tablas con la sintaxis que define las expresiones regulares. Puede ayudaros a entender mejor las dos que os he presentado y puede ayudaros a generar otras nuevas.

 

Algunos metasímbolos usados en las expresiones regulares

*El elemento precedente debe aparecer 0 o más veces
+El elemento precedente debe aparecer 1 o más veces
.Un carácter cualquiera excepto salto de línea
?Operador unario. El elemento precedente es opcional
{n}Que coincida exactamente n veces
{n,}Que coincida al menos n veces
{n,m}Que coincida al menos n veces y no mas de m
|O uno u otro
^Comienzo de línea
$Fin de línea
.Cualquier carácter que no sea el retorno de carro
[...]Conjunto de caracteres admitidos
[^...]Conjunto de caracteres no admitidos
-Operador de rango
(...)Agrupación
\Escape
\nRepresentación del carácter fin de línea
\tRepresentación del carácter de tabulación

 

Abreviaturas para las clases más comunes en las expresiones regulares

CódigoSignificado
\d[0-9] Dígitos del 0 al 9
\D[^0-9] Carácter que no sea un dígito
\w[a-zA-Z0-9_] Carácter alfanumérico
\W[^a-zA-Z0-9_] Carácter no alfanumérico
\s[ \t\n\r\f] Espacio en blanco
\S[^ \t\n\r\f] Carácter que no es un espacio en blanco

 

No obstante la definición de estas expresiones, dependiendo de la dificultad del patrón a definir, puede no siempre ser trivial. A esto se le suma la experiencia que pueda tener cada uno para definir dichas expresiones.  Por eso herramientas como RegExr me parecen imprescindibles: una herramienta online para aprender, construir y probar expresiones regulares.

RegExr: http://regexr.com

RegExr_screenshot

Algunas de las características más destacadas de RegExr son:

  • Resultados actualizados en tiempo real, mientras tecleas
  • Información detallada de cada expresión cuando pasas sobre ella
  • Extensa batería de ejemplos y chuletas
  • Deshacer y Rehacer muy sencillo
  • Puedes compartir tus patrones y expresiones y votar las del resto de la comunidad (y "favoritearlas")

Si queréis recordar/practicar expresiones regulares, o simplemente queréis aprender practicando, os animo a que hagáis algunas pruebas con la herramienta. Recordad que podéis probar a usar las dos expresiones que aparecen en esta entrada si no sabéis por donde empezar.

MeshlabServer – Aplicación de filtros de Meshlab en lote

En mi día a día trabajo con información tridimensional y hago tratamiento de la misma mediante una herramienta que se ha convertido para mí en un imprescindible. Se trata de Meshlab.

Meshlab es una herramienta Open Source  muy potente que permite el manejo y procesamiento de información 3D. Lo que hace realmente potente a Meshlab, son la cantidad de filtros para procesar esa información, y que más de uno ha pensado en usar como herramienta para hacer cierto procesamiento de un Dataset de información.

Cuando se descargan los binarios de Meshlab, se incluyen dos ejecutables: meshlab y meshlabserver. El primero es obvio para qué sirve, porque se trata del ejecutable que lanza Meshlab para ser utilizado por medio de la interfaz gráfica. El segundo es una ejecutable que nos permite procesar un Dataset completo, usando los filtros de Meshlab, mediante la configuración de un script MLX y prescindiendo de la interfaz gráfica.

Generar el script es tan sencillo como abrir Meshlab y aplicar todos los filtros que deseemos en el Dataset. Veamos un ejemplo.

Yoshi

Tenemos la malla de un modelo 3D de Yoshi como Dataset, pero dicho modelo tiene un agujero en la parte inferior.

Yoshi_with_hole

Meshlab dispone entre sus filtros de uno que se llama "Close Holes", que nos vendrá de perlas para este caso. Vamos a la sección "Filters" y los buscamos.

Meshlab_close_hole

Parametrizamos el filtro como mejor consideremos y le damos a aplicar. Como podemos ver el agujero de la parte inferior queda cerrado.

Yoshi_no_hole

Para generar el script del filtro que acabamos de aplicar y que vemos que da buenos resultados, volvemos a ir a "Filters", y seleccionamos "Show current filter script". Se nos abrirá una ventana como la siguiente:

Meshlab_script

Aquí están todas las acciones que van a constituir nuestro script, en nuestro caso sólo vamos a usar "Close Holes". En esta ventana podemos editar el orden de los filtros que vamos a aplicar, los parámetros  de cada script, borrar un  filtro del script... Cuando todo está en orden guardamos el script, el cual será guardado en formato MLX.

Para aplicar las acciones en lote sólo tenemos que usar el ejecutable meshlabserver indicándole los parámetros necesarios para su funcionamiento (input, output y script de filtros XML). Para ver la parametrización de meshlabserver podemos acudir a su comando de ayuda de la siguiente forma:

meshlabserver -help
Usage:
    meshlabserver arg1 arg2 ...
where args can be:
 -i [filename...]  mesh(s) that has to be loaded
 -o [filename...]  mesh(s) where to write the result(s)
 -s filename		    script to be applied
 -d filename       dump on a text file a list of all the filtering fucntion
 -l filename       the log of the filters is ouput on a file
 -om options       data to save in the output files: vc -> vertex colors, vf -> vertex flags, vq -> vertex quality, vn-> vertex normals, vt -> vertex texture coords,  fc -> face colors, ff -> face flags, fq -> face quality, fn-> face normals,  wc -> wedge colors, wn-> wedge normals, wt -> wedge texture coords
Example:
	'meshlabserver -i input.obj -o output.ply -s meshclean.mlx -om vc fq wn'

Notes:

There can be multiple meshes loaded and the order they are listed matters because
filters that use meshes as parameters choose the mesh based on the order.
The number of output meshes must be either one or equal to the number of input meshes.
If the number of output meshes is one then only the first mesh in the input list is saved.
The format of the output mesh is guessed by the used extension.
Script is optional and must be in the format saved by MeshLab.

De esta forma podemos aplicar una sucesión de operaciones de Meshlab en el Dataset que queramos con muy poco esfuerzo.