Intercalar Shell scripting con texto / HTML / XML / Markdown / etc

El pequeño pero genial script awk que se presenta en este articulo forma parte del proyecto webrc, un “anti-framework” web minimalista construido siguiendo la filosofía de diseño de Unix y Plan 9. Este script permite crear un documento en formato texto, por ejemplo xml, markdown o html, pero integrando en su contenido lógica de la terminal, es decir, intercalar dentro condiciones, variables, salidas de comandos y cualquier otra cosa que se pueda realizar en una terminal para generar contenido dinámico.

El uso es similar a como se programa en PHP, usando unas etiquetas para insertar el código entre texto. La forma de uso en este caso es agregar el carácter “%” a principio de linea para que la linea sea interpretada por una shell, la cual no necesariamente tiene que ser Bash. Es muy útil a la hora de generar informes / documentación. Veamos un ejemplo de uso práctico para entender bien la utilidad de dicho script.

Código del script template.awk: https://code.9front.org/hg/werc/file/fb460a671d19

#!/bin/awk -f
function pr(str) {
	if(lastc !~ "[{(]")
		gsub(/'/, "''", str)
	printf "%s", str
}
function trans(c) {
	printf "%s", end
 
	lastc = c
	end = "\n"
	if(c == "%")
		end = ""
	else if(c == "(")
		printf "echo -n "
	else if(c ~ "[})]") {
		end = "'\n"
		printf "echo -n '"
	}
}
 
BEGIN {
	lastc = "{"
	trans("}")
}
END {
	print end
}
 
/^%/ && $0 !~ /^%[{()}%]/ && lastc !~ /[({]/ {
	trans("%")
	print substr($0, 2)
	next
}
{
	if(lastc == "%")
		trans("}")
	n = split($0, a, "%")
	pr(a[1])
	for(i=2; i<=n; i++) {
		c = substr(a[i], 1, 1)
		rest = substr(a[i], 2)
 
		if((lastc !~ "[({]" && c ~ "[({]") ||
		   (lastc == "{" && c == "}") ||
		   (lastc == "(" && c == ")"))
			trans(c)
		else if(c == "%")
			pr("%")
		else
			pr("%" c)
		pr(rest)
	}
	pr("\n")
}

Generar contenido html dinámico de ejemplo, se crea un fichero con nombre test que tendrá el siguiente contenido.

% # Declaración de tres variables.
%   nombre=Marisa
%   apellido=Gutiérrez
%   uid=`id`
% # Código HTML usando variables, condiciones y comandos bash.
 
<html>                                                                                                                           
   <head>
      <title>Web de '%($nombre $apellido%)'</title>
   </head>
   <body>
 
% if [[ $EUID -eq 0 ]]; then   # Establecemos una condición ofreciendo dos posibles salidas dependiendo del uid.
      El usuario es Root <b>'%($uid%)'</b><br>
%else 
      La Variable del sistema $USER dice que el usuario es %($USER%) y tiene los siguientes IDs <b>%($uid%)</b>
%fi
<br><br>Estos son los archivos del directorio donde se ejecutó el comando "ls -lt".
      <pre>  
%  ls -lt    # Ejecución de un comando de Linux que listará el directorio actual y quedará entre etiquetas <pre>
      </pre>
   </body>
</html>

Ejecutamos de la siguiente manera el fichero test.

./template.awk test | bash 

El resultado como se puede ver es el código html con el contenido dinámico generado mediante instrucciones shell (variables locales, variables de entorno, condición y salida del comando ls).

<html>
   <head>
      <title>Web de Marisa Gutierrez</title>
   </head>
   <body>
 
      La Variable del sistema $USER dice que el usuario es Mari y tiene los siguientes IDs <b>uid=1000(Mari) gid=1000(Mari) grupos=1000(Mari),108(vboxusers)</b>
<br><br>Estos son los archivos del directorio donde se ejecutó el comando "ls -lt".
      <pre>
total 9275784
-rw-r--r--  1 Mari Mari        777 mar 30 21:38  test
-rw-r--r--  1 Mari Mari      13834 mar 30 21:35  backup.log
drwxr-xr-x  6 Mari Mari       4096 mar 30 21:28  Backups_web
-rw-r--r--  1 Mari Mari      60198 mar 30 21:28  calendar.ics
...
      </pre>
   </body>
</html>