Ejecutar un programa SAS pasando parámetros

La entrada de hoy es la solución a un problema muy fácil: se trata de planificar un programa sas pasándole algún parámetros desde línea de comandos, en este caso, la solución aplica a Unix/Linux.

Para ello, debemos crear un fichero de script (.sh) que contenga la llamada y los parámetros a enviar:

sh [ruta_SAS]/Lev1/SASApp/sas.sh -set fecha 20201111 -set hora 17:28 -sysin [ruta_programa]/programa.sas -log [ruta_log]/fichero.log

La llamada a sas.sh ejecuta sas.exe con las opciones que estén configuradas para el usuario. El parámetro set contiene una dupla clave valor con el nombre de la variable a enviar al programa en ejecución y su valor. Se pueden concatenar varios parámetros set. En el ejemplo se pasa la fecha y la hora. Finalmente, los parámetros sysin y log indican la ruta y fichero del programa sas y del log que se debe generar, respectivamente.

Una vez hecho esto, solo queda recoger en el programa los valores que hemos enviado. Esto podemos hacerlo de la siguiente forma:

%let fecha=%sysget(fecha);
%let hora=%sysget(hora);

Con ello, podemos utilizar los parámetros que hemos enviado como simples macrovariables: &fecha y &hora.

Unix: Extensión de un fichero Unix

En esta ocasión vamos a ver cómo podemos hacer con un script de Unix una tarea que en realidad también podemos hacer con SAS. Se trata de renombrar ficheros *.zip a *.zip.old, en este caso modificando su extensión. Para ello, debemos poder extraer las dos partes del nombre de un fichero: el nombre y la extensión.

FICHERO="${i%%.*}"
EXTENSION=$([[ "$i" = *.* ]] && echo "${i#.}" || echo "${i##.}")

Si queremos procesar todos los ficheros zip de un directorio para renombrarlos recursivamente a zip.old (por ejemplo) podemos usar el siguiente script. Lo primero que hace es listar los ficheros que tienen zip en su nombre (o extensión). Luego revisa, para cada uno de ellos, cual es exactamente su extensión, y si finalmente tienen extensión zip los renombra (con mv) a *.zip.old:

for i in $(ls -1 | grep .zip);
do FICHERO="${i%%.*}";
EXTENSION=$([[ "$i" = *.* ]] && echo "${i#.}" || echo "${i##.}");
if [ "$EXTENSION" == "zip" ];
then mv $FICHERO.zip $FICHERO.zip.old;
fi;
done

Este script puede ser llamado también desde SAS para hacer esa misma tarea con el comando X:

x"for i in $(ls -1 | grep .zip); do FICHERO="${i%%.*}"; EXTENSION=$([[ "$i" = *.* ]] && echo "${i#.}" || echo "${i##.}"); if [ "$EXTENSION" == "zip" ]; then mv $FICHERO.zip $FICHERO.zip.old; fi; done";

Administración SAS: Detección sesiones pesadas

Este procedimiento sirve a aquellos administradores de un sistema SAS a determinar que sesión y que usuario pueden llegar a estar dando problemas al resto en un momento dado por estar consumiendo demasiado espacio en disco en el servidor.

Para poder ejecutarlo es necesario tener un usuario en el sistema operativo de la máquina SAS con permisos sudo. Este procedimiento está, por tanto, dirigido a máquinas Linux y se lo debo a mi compañero y amigo Christian.

Tras logarnos nos adjudicamos permisos sudo: sudo su -

sesiones1

Nos dirigimos a la ruta donde está la work, típicamente /opt/sas/saswork/. En esta carpeta se encuentran almacenadas las carpetas Linux que contienen todos los datos almacenados en todas las work de todas las sesiones SAS abiertas en ese momento por todos los usuarios en esa máquina. Listamos los nombres de esas work y determinamos cuales pueden ser más grandes y dar problemas, por ejemplo hacemos un grep para coger aquellas sesiones que están expresadas en Gb: du -sh * | grep G

sesiones2

Podemos ver que efectivamente las work están almacenadas en esa ruta de nuestro servidor si desde Enterprise Guide sacamos las propiedades de nuestra work con el botón derecho. La ruta que nos indica es exactamente esa.

sesiones3

Finalmente para identificar al usuario ‘infractor’ hacemos un grep del log de su sesión buscando su CLIENTMACINE, que no es más que su identificador de usuario. Se puede hacer también un grep a CLIENTUSERID que contiene el nombre del usuario:

grep CLIENTUSERID SASApp_WorkspaceServer_2018-11-07_sas_5889.log

En el caso de que estuviéramos buscando una sesión que se haya quedado colgada la tarea de identificarla es siempre muy fácil si los usuarios ejecutan un %put &sysjobid; porque reflejará el PID de esa tarea en el log y sabremos que tarea matar. Lo realmente idóneo es incluir esta instrucción en el autoexec.sas.

Automatización de procesos con SAS

SAS Enterprise Guide tiene un planificador de tareas que no está mal pero también se puede planificar tareas en el propio servidor. La solución que os ofrezco está basada en un servidor con un sistema operativo Linux.

Una automatización tiene 3 partes: el código SAS a ejecutar, un script que llama al programa y un planificador de tareas que llama al anterior.

Programa SAS (fichero .sas)

Es necesario eliminar de él cualquier rastro de parámetro o fecha variable que hallamos estado empleando cuando lo desarrollamos y debemos calcular esos valores en función de la información que tendremos en la máquina en el momento de la ejecución: como por ejemplo la fecha de sistema. Si queremos hacer un cierre de mes lo más sensato será calcular la fecha de cierre como:

fecha_ejecución = intnx('month',date(),-1,'E');

 
Además recomiendo incluir al principio del programa la siguiente línea que imprime en el log del proceso el número de tarea que se está ejecutando. De esa manera podremos matar un proceso colgado con un comando kill.

%put &sysjobid;

 
TIP: Al hacer una primera automatización es recomendable verificar cual es la fecha del sistema en el servidor SAS, porque podría ser distinta a la actual y eso puede generar problemas.

Script (fichero .sh)

Este pequeño programa es el encargado de identificar la ruta donde se encuentra [sas.exe] y en este caso utiliza además otro script [sas.sh] para que se ejecuten los parámetros de ejecución de sas.exe. También necesita la ruta y el nombre del programa .sas a ejecutar y la ruta y nombre del fichero que se creará con el log de la ejecución. Es importante tener en cuenta esto porque sino nunca sabremos por qué fallan nuestros procesos.

#!/bin/sh
f_job=[ruta_programa]/[nombre_programa].sas
f_log_sas=[ruta_log]/`date +%Y%m%d%H%M`_"$1"[nombre_log].log
sh [ruta_base_sas]/sas.sh -sysin ${f_job} -log ${f_log_sas}

 
Ambos ficheros el .sas y el .sh deben ser copiados con FileZilla u otra herramienta similar a las rutas que hemos visto.

Planificador de tareas

Utilizo el planificador de tareas de Linuz, CRON. Cron tiene un demonio corriendo en el sistema operativo que lanza las tareas que se han indicado en un fichero de texto: crontab. Cada usuario del sistema tiene un fichero crontab para sus propias tareas.

En nuestro caso, para que SAS tenga permisos sobre las ficheros y tablas que necesitamos utilizar en nuestro proceso es necesario utilizar un usuario de Linux que sea también usuario en SAS. Existen varios usuarios de esta naturaleza en una instalación de SAS: sasbatch, sasdemo, etc. El adecuado para planificar un proceso es sasbatch.

Para editar el fichero crontab debemos logarnos en la máquina y acceder al shell para introducir este comando:

crontab

El programa se abre con el visor vi. Para editarlo pulsamos [INSERT]. A continuación introduciremos una línea por programa sas a planificar. Finalmente introducimos las combinaciones de teclas: [END]:q! para salir sin guardar y [ESC]:wq para salvar y salir. No voy a entrar definir aquí como se planifica una tarea pero os dejo un enlace a la Wikipedia donde se explica muy bien:

En un próximo post comentaré errores típicos que se pueden producen al planificar.