educación, informática y demás

GNU/Linux bash, Shell scripts

Funciones

Podríamos ver una función como un script dentro de un script. Gracias a las funciones podemos agrupar una serie de comandos que se ejecutan uno detrás de otro al invocar o llamar a la función.

A las funciones, igual que a los scripts, se les puede pasar valores por parámetro. Para pasar valores por parámetro tan solo tenemos que escribir los valores que queramos pasar después del nombre de la función. Para leerlos tan solo tenemos que utilizar las variables especiales $1..$9 dentro de la función.

Ejemplo 01 – Función sintaxis

Muchas veces en nuestros scripts recibimos parámetros.No estaría mal advertir al usuario de los parámetros que debe recibir nuestra función o de los requisitos que tiene.

Para ello, podríamos utilizar una función encargada exclusivamente de esto.

Vamos a mostrar la sintaxis del comando antes de realizar ninguna operación.

Vamos a usar una función exclusiva para mostrar la sintaxis.

Cada vez que ejecutemos «sintaxis» se van a ejecutar, en orden, los comandos de la función, como si fuera un script dentro de nuestro script.

Como no se ha pasado parámetro, se cumple la condición del primer if:

Como está vacía la variable file, el comando test – z $file devolverá un código de salida de OK y se ejecutará el cuerpo del then o los comandos que están en el then, comenzando por el comando de la línea 25, que es una llamada a la función sintaxis.

Al ejecutar sintaxis, se ejecutarán los comandos de esta función.

Una vez terminen de ejecutarse todos los comandos de la función sintaxis, la shell seguirá ejecutando por la siguiente línea o siguiente comando después de la llamada a la función sintaxis, es decir la línea 26 y después la línea 27

La línea 27 ejecutará un comando exit que termina con la ejecución del script.

Ejemplo 02 – Función error

En los dos cuerpos de los then que se encargan de comprobar o controlar los errores, hacemos exactamente lo mismo, con la excepción de que el mensaje que se muestra al usuario es diferente, porque queremos advertir al usuario de cuál es el error que se ha producido para que lo corrija.

¿Y si sacamos esos comandos que se repiten en varias partes del script y los metemos en una función para reutilizarlos?

Primero determinamos el nombre de la función, error. La escribimos y la delimitamos con las llaves de apertura y cierre.

Ahora CTRL+C, CTRL+V.

El mensaje que muestra esta función error es propio del error que se produce cuando el usuario no pasa ningún valor por parámetro. Esto haría que esta función fuera utilizada solo en un caso. Lo que vamos a hacer es obtener por parámetro el mensaje a mostrar.

Los parámetros dentro de una función se utilizan igual que los del script, con las variables especiales $1 a $9. Si accedemos a $1 dentro de una función estaremos accediendo al parámetro número 1 de la función, no del script.

Así quedaría el script

Cuidado con los $1 que aparecen en el script. Dependiendo de si están dentro de una función o fuera de ella harán referencia al parámetro pasado a la función o al script.

Vamos a echar un vistazo a todo el script

Ahora vamos a centrarnos solo en las funciones. Trata de responder la siguiente pregunta para cada función, ¿qué hace la función?.

Hemos utilizado nombres de función significativos y además el código de cada una es bastante comprensible

Ahora, vamos a ver solo el código fuente de la parte principal del script, teniendo en cuenta los controles de error y adquisición de datos.

Vamos a sacar el procesado de datos de los cursos en una función. Recibiremos la línea del fichero en el primer parámetro. Así que, para dejar casi sin tocar las líneas de código del cuerpo del bucle, asignaremos a una variable llamada datos dentro de la función lo que recibamos en el primer parámetro

Ahora, tenemos que cambiar el cuerpo del bucle for para que llame a la función procesaCurso pasándo por parámetro la variable datos, que contiene la línea que acaba de leer del fichero.

De esta forma, el cuerpo del script quedaría de esta manera, mucho más comprensible. si queremos saber qué se hace con cada dato, tendríamos que leer la función procesaCurso.

Ejercicio 04 – Desarrolla procesa curso

Este es el fichero de datos que recorremos:

Ahora que tenemos todo organizadito, vamos a ver si somos capaces de darle funcionalidad a la función procesaCurso.

Queremos que, para cada curso, comprobemos si existe el grupo en el sistema con el nombre del curso. Si no existe el grupo, creamos un nuevo grupo con el nombre del curso.

A continuación, comprobamos si existe el directorio del curso. Este directorio tendrá el nombre del curso y estar´a almacenado en /educatica/cursos.

Si no existe el directorio del curso, lo creamos.

Después, nos aseguramos de que el directorio del curso pertenezca al grupo del curso y dicho grupo tenga todos los permisos de acceso a dicho directorio.

Por último, pero no menos importante, para cada miembro o alumno del curso, vamos a comprobar si existe cuenta de usuario en el sistema. Si no existe cuenta de usuario para ese usuario, añadimos cuenta de usuario.

Después, comprobamos si el usuario es miembro del grupo del curso. Si no es miembro, lo añadimos.

Más o menos, la función procesaCurso tendrá la siguiente pinta:

Ahora tenemos que resolver cómo comprobamos:

  • Si el grupo no existe
  • Si el directorio no existe
  • Recorrer los alumnos que están en la variable $miembros

Piensa primero cómo lo harías tu, como administrador, desde una terminal. Es decir, ¿Cómo comprobarías tu que el grupo, por ejemplo, contabilidad existe en el sistema?. Después trata de utilizar ese comando en la sentencia if.

Lo bueno que tiene trabajar con funciones, es que nos centramos en el problema que trata de resolver la función y nos olvidamos del resto.

Javier

Comprobando si un grupo existe

Primero, si no lo tenemos claro, podemos trabajar con la consola o el shell para ver que comando o comandos usaríamos como administradores para comprobar si un grupo existe en el sistema.

Sabemos que la información de grupos se almacenan en /etc/group, así que podemos buscar información ahí. Por ejemplo, del grupo educatica.

Mostrando las líneas que contengan la palabra educatica en /etc/group
Muestra las líneas del fichero /etc/group que contengan la cadena de texto educatica completa, es decir tal cual, al comienzo de la línea.

Podríamos sacar esto así…

Comprobar si un directorio existe

Vamos a usar el comando test con la opción -d. Consultemos la ayuda de test.

Recorrer miembros

Aquí tenemos un problema. La lista de miembros contiene nombre de usuarios, pero separados por comas, no por espacios. El bucle for no podrá recorrer esta lista de elementos así, como aparece.

Tenemos una opción, traducir o sustituir previamente las comas «,» por espacios » «. Para ello, podemos usar el comando tr. Mira la ayuda del comando tr.

Solución de la función

Ejemplo – Función simple que trabaja con variable global

Puede que haya veces en las que una función tenga que trabajar con una o varias variables globales del script. Esto es, que asigne datos a una variable que será utilizada fuera de la función o que lea datos de una variable definida fuera de la función.

A continuación tienes un ejemplo de este uso

En este caso, la función pideDirectorio lee la variable global asignada en la línea 19, fuera de la función, y asigna un valor obtenido por teclado en la variable directorio que será utilizada fuera de la función.

Este tipo de uso de variables globales puede ser peligroso, puesto que es difícil detectar errores humanos introducidos en alguna función que utilice alguna de estas variables. No obstante, habrá veces en las que sea necesario su uso.

Un detalle, parece que la función pideDirectorio utiliza la variable baseDir antes de que se le haya asignado un valor. La línea 9 hace uso de la variable baseDir no obstante esta variable no se declara asginándole un valor hasta la línea 19. Sin embargo, la línea 9 no se ejecutará hasta que no se ejecute la función. La primera vez que se ejecuta la función es en la línea 21, después de que se haya declarado la variable baseDir.

Dejar una respuesta