Laboratorio de Herramientas Computacionales Programación del Shell 1. Introducción. El intérprete de comandos o Shell es la interfaz principal entre el usuario y el sistema, y que le permite al usuario interactuar con los recursos de sistema. El usuario introduce sus órdenes, el intérprete las procesa y genera la salida correspondiente. Por lo tanto, un intérprete de comandos de Linux es tanto una interfaz de ejecución de órdenes y utilidades, como un lenguaje de programación, que admite crear nuevas órdenes (denominadas guiones o scripts de shell o shellscript), utilizando combinaciones de comandos y estructuras lógicas de control. En Unix existen 2 familias principales de intérpretes de mandatos: los basados en el intérprete de Bourne (BSH, KSH o BASH) y los basados en el intérprete C (CSH o TCSH). En este curso de Laboratorio de Herramientas Computacionales haremos uso de BASH. Configuración del entorno de operación. El intérprete de comandos de cada cuenta de usuario tiene un entorno de operación propio, en el que se incluyen una serie de variables de configuración. El administrador del sistema asignará unas variables para el entorno de ejecución comunes a cada grupo de usuarios –o a todos ellos–; mientras que cada usuario puede personalizar algunas de estas características en su perfil de entrada, añadiendo o modificando las variables. • Para crear el entorno global, el administrador crea un perfil de entrada común para todos los usuarios editando el archivo /etc/bashrc (en el caso de BASH), donde se definen las variables del sistema y se ejecutan los archivos de configuración propios para cada aplicación. Estos archivos son pequeños programas o scripts (archivos propios de los intérpretes de comandos basados en el de Bourne (BSH, BASH, etc), con extensión .sh, y otros para los basados en el intérprete C (CSH, TCSH,etc.), con extensión .csh) y que se sitúan en el subdirectorio /etc/profile.d. • El proceso de interacción del usuario se completa con la ejecución del perfil de entrada personal del usuario (archivo ~/.bash_profile para BASH). Aunque el administrador debe suministrar un perfil válido, el usuario puede editar dicho archivo a su conveniencia. M.I. Rosalía Mora Juárez FIE 2010 1 Laboratorio de Herramientas Computacionales Recomendaciones de programación. Como cualquier otro programa, un script de shell puede requerir un cierto mantenimiento, que incluya modificaciones, actualizaciones o mejoras del código. Por lo tanto, al escribir nuestros scripts debemos tomar en cuenta las recomendaciones de desarrollo típicas para cualquier programa. A continuación se presentan algunas recomendaciones: • El código debe ser fácilmente legible, incluyendo espacios y sangrías que separen claramente los bloques de código • Deben añadirse comentarios claros sobre el funcionamiento general del programa. principal y de las funciones. Se recomienda que contengan: autor, descripción, modo de uso del programa, versión y fechas de modificaciones. • Incluir comentarios para los bloques o mandatos importantes, que requieran cierta aclaración. • Agregar comentarios y ayudas sobre la ejecución del programa. • Depurar el código para evitar errores, procesando correctamente los parámetros de ejecución. • No desarrollar un código excesivamente complicado de leer, aunque esto nos haga ahorrar líneas de programa. • Utilizar funciones y las estructuras de programación más adecuadas para evitar repetir código reiterativo. • Todos los nombres de funciones y de programas deben escribirse en letras minúsculas, mientras que para las variables se acostumbra usar mayúsculas. • Los nombres de variables, funciones y programas deben ser descriptivos, cuidando de no confundirse con otras de ellas, ni con los mandatos internos o externos del Shell; los nombres no deben ser ni muy largos ni muy cortos. Edición y ejecución de un script de shell. Un script de shell interpretado por BASH es un archivo de texto normal que consta de una serie de bloques de código formados por líneas de mandatos que se ejecutan en secuencia. El usuario debe tener los permisos de modificación (escritura) en el directorio –para crear un nuevo programa– o sobre el propio archivo, para modificar uno existente. Si el programa se encuentra en un directorio incluido en la variable de entorno PATH, sólo se necesita teclear el nombre, sin necesidad de especificar el camino (Ver PATH en la sección variables de ambiente). M.I. Rosalía Mora Juárez FIE 2010 2 Laboratorio de Herramientas Computacionales Proceso de edición y ejecución de un script El proceso completo de edición y ejecución de un script es muy simple; Básicamente consta de 3 pasos: 1. Utiliza un editor de textos para escribir el script. Por convención, la extensión para los scripts de shell es .sh, así que guardaremos nuestro script con dicha extensión. vi prueba.sh 2. Aquí usamos vi, pero puede ser cualquier otro editor de textos Activa los permiso de ejecución para el script creado: chmod u+x prueba.sh 3. Ejecuta el script: ./prueba.sh o bien sh prueba.sh si el script está en el directorio actual si el script está en un directorio de contenido en la $PATH Ahora vamos a crear nuestro primer script, y lo llamaremos primero.sh. Escribiremos como contenido lo siguiente: #!/bin/sh echo Este es mi primer script! Nótese que el script de shell inicia con dos líneas básicamente: • Un comentario (los comentarios son ignorados por el intérprete de comandos), que inicia con el caracter #, y todo lo que se escriba después hasta el final de esa línea será tomado como un comentario. Por lo general se escribe la secuencia #! /bin/sh, misma que indica al shell que /bin/sh es el programa que se debe usar para ejecutar este archivo. • La primera línea "ejecutable". Aquí ya se incluyen uno o varios comandos que interactúan con el intérprete, el flujo de datos, la entrada y salida estándar (stdin, stdout) y los descriptores de error. Una vez que ya hemos escrito nuestro script de shell, guardamos el archivo. Recuerda que si intentamos ejecutarlo no funcionará (a menos que el directorio de trabajo este contenido en la variable path). Esto es porque la extensión .sh no lo hace un archivo ejecutable. Para que se pueda ejecutar tenemos que asignarle permisos de ejecución: chmod u+x script.sh NOTA: otra forma de otorgar los permisos es escribir chmod 500 o chmod +x. M.I. Rosalía Mora Juárez FIE 2010 3 Laboratorio de Herramientas Computacionales Ahora sí nuestro script es ejecutable!. Tenemos 2 opciones para ejecutarlo: • Ejecutar con: ./primero.sh • Ejecutar con: sh primero.sh Variables Las variables son "palabras" que contienen un valor. El Shell nos permite crear, asignar y eliminar variables. El nombre de una variable puede contener solo letras (de a a z o de A a Z), números (0 a 9) o el caracter de guión bajo ( _ ). Adicionalmente el nombre de una variable solo puede comenzar con una letra o un guión bajo. Algunos ejemplos de nombres de variables válidas son: _TOTAL NUMERO_TOTAL archivo1 _datos nombre_de_archivo sin embargo, el siguiente nombre no es válido. 2resultado Para corregir el error anterior se puede agregar un guion bajo al principio: _2resultado Nombres de variables tales como 1, 2 u 11 tampoco son válidos porque comienzan con un número, y los números están reservados para ser utilizados por el Shell en los descriptores. Como usuario podemos utilizar el valor almacenado en esas variables, pero generalmente no podremos asignarles valores a esas variables. En los nombres de variables tampoco se pueden utilizar caracteres como !, * o - . Recuerda que estos caracteres tienen un significado especial para el Shell. M.I. Rosalía Mora Juárez FIE 2010 4 Laboratorio de Herramientas Computacionales Tipos de variables. Las variables del intérprete de comandos basado en BASH por convención se clasifican como a continuación se describe. Variables locales Las variables locales son definidas por el usuario y se utilizan únicamente dentro de un bloque de código, de una función determinada o de un guión. Un ejemplo es: VAR1=Hola echo $VAR1 Hola Como se puede observar en el ejemplo anterior, para asignar valores a una variable se utiliza simplemente su nombre, pero para hacer referencia a su valor hay que utilizar el símbolo $. El siguiente ejemplo muestra los modos de referirse a una variable. ERR=2 echo ERR ERR echo $ERR 2 Se le asigna 2 a la variable ERR. Muestra como resultado la cadena "ERR" Muestra como resultado el valor por referencia de la variable ERR Para quitarle el valor a una variable podemos utilizar el comando unset. $ $ 1 $ $ X X=1 echo $X unset X echo X Variables de ambiente o entorno Las variables de ambiente o entorno son las que afectan tanto al comportamiento del intérprete como el comportamiento de la interfaz del usuario. Son variables que están disponibles para cualquier proceso invocado por el Shell. Algunos programas requieren variables de ambiente para funcionar correctamente. M.I. Rosalía Mora Juárez FIE 2010 5 Laboratorio de Herramientas Computacionales La siguiente tabla presenta las principales variables de ambiente. VARIABLE DEFINICION PPID Número de identificación del proceso padre de la interfaz de comandos. PWD Directorio de trabajo actual, establecido por el comando cd. OLDPWD REPLY UID Anterior directorio de trabajo, establecido por el comando cd. Cuando se usa el comando read de bash sin argumentos, esta variable recoge el contenido de la línea leída. Número identificativo (ID) del usuario, establecida en el arranque del shell. EUID ID eficaz de usuario, inicializada en el arranque del shell. BASH Nombre completo, incluida la ruta, del archivo que se ejecutó para lanzar el shell. BASH_VERSION Número de versión de Bash. SHLVL Nivel del shell. Incrementa su valor en una unidad cada vez que se lanza una nueva interfaz de comandos. RANDOM Cada vez que se invoca a esta variable se obtiene un número entero aleatorio. La secuencia de números aleatorios proporcionadas por RAMDOM se puede inicializar simplemente asignándole un nuevo valor a esta variable. SECONDS Mantiene el número de segundos que han transcurrido desde que se ejecutó el shell. Si asignamos un valor a esta variable, la cuenta indicará los segundos transcurridos desde dicha asignación, mas el valor asignado. LINENO Cuando se hace referencia a esta variable desde un script, indica la línea dentro del script en la que se le esta haciendo referencia, considerando que la primera línea se numera como 1. Si se invoca desde la propia interfaz de comandos, el valor que devuelve es el número de línea que hace la orden ejecutada desde que se inició la interfaz de comandos. HISTCMD Contiene la posición dentro del archivo de historia de comandos que ocupa el comando actual. HOSTTYPE Se trata de una cadena de texto describiendo el tipo de máquina en la que esta ejecutando el bash. HOSTNAME Nombre de la máquina. OSTYPE Se trata de una cadena de texto describiendo el sistema operativo en el que sé está ejecutando el bash. PATH La ruta de búsqueda de comandos. Se trata de una secuencia de directorios en los que localizar los programas, separados entre sí por un signo de dos puntos (:). La interfaz de comandos recorrerá esta lista en el orden dado buscando los comandos que queramos ejecutar. HOME Directorio raíz del usuario actual. Es el argumento usado por defecto cuando ejecutamos el comando cd sin especificar ninguno. CDPATH Se trata de la ruta de búsqueda para el cd. Tiene una estructura similar a la variable PATH. Lo que indica es donde se deben buscar los directorios especificados como argumentos al comando. Como ejemplo habitual, podría M.I. Rosalía Mora Juárez FIE 2010 6 Laboratorio de Herramientas Computacionales VARIABLE DEFINICION contener :~:/usr. MAIL Cuando contiene el nombre de un archivo, bash comprueba en él la llegada de correo nuevo y avisa en caso que se produzca. MAILCHECK Determina el intervalo de tiempo en segundos que bash tomará para revisar si hay correos nuevos. MAILPATH Al igual que PATH y CDPATH, esta variable contiene una lista, en este caso, de archivos que deberán ser comprobados para la posible llegada de correo. Se puede indicar un mensaje especifico para la llegada de correo en diferentes buzones usando el carácter '?' como separador entre el archivo y el mensaje. En ese caso, la variable $_ obtendrá el nombre del buzón. Un ejemplo: MAILPATH='/var/spool/mail/nlucas?"Tienes correo":~/mail/buzon?"Ha llegado algo al $_"' PS1 Valor del prompt principal. PS2 Valor del prompt secundario. Este prompt es el que aparece cuando partimos una línea en la interfaz de comandos para continuar introduciendo en la siguiente línea de la pantalla. PS3 Valor del tercer prompt. Este prompt es usado solamente por el comando select. PS4 Valor del cuarto prompt y último. Tan solo se usa cuando se está realizando un seguimiento de los comandos mostrándose para indicar los pasos por los que se va ejecutando el comando. Para entrar en el modo de seguimiento, basta con ejecutar set -x. Entonces veremos cómo cada comando que ejecutemos se expande, mostrando las sustituciones que se hacen con los alias, las variables, etc. HISTSIZE Contiene él número de comandos a guardar en el historial de comandos. HISTFILE Contiene el nombre del archivo en el que se almacena el historial de comandos. Por defecto se trata del archivo ~/.bash_history. HISTFILESIZE Número máximo de líneas que puede contener el archivo de historial. Tengamos en cuenta que un comando puede ocupar varias líneas. PROMPT_COMMAND Si está definido, contiene el comando a ejecutar antes de presentar el prompt. IGNOREEOF Indica cuantas veces ha de recibir el carácter EOF (End Of File, o la pulsación de la tecla Crtl-D) antes de salir de bash. Si el valor indicado no es numérico, se toma por defecto el 10. Si no esta seleccionado, una única pulsación basta. TMOUT Si contiene un valor superior a cero, indica el número de segundos que se puede estar sin introducir un comando al Shell. Pasado este tiempo, la interfaz de comandos se cerrará. FCEDIT Ruta y nombre del editor usado por defecto para el comando fc. Por defecto se usa Vi . FIGNORE Lista de sufijos de archivos que se ignoraran al intentar completar un nombre de archivo desde bash. La lista estará formada por los sufijos ignorados, separados por un signo de dos puntos (:). Por ejemplo .0:.tmp M.I. Rosalía Mora Juárez FIE 2010 7 Laboratorio de Herramientas Computacionales VARIABLE DEFINICION EDITOR En esta variable muchos programas buscaran la ruta y el nombre del editor a usar. Por defecto el editor usado es el Vi. Algunos de los programas que hacen uso de esta variable son crontab (con la opción -e), edquota y otros muchos. TERM Contiene el tipo de terminal. Esta variable es importante, pues algunos tipos de terminales no son compatibles con algunos programas. Para desplegar todas las variables (y sus valores) que el Shell controla podemos utilizar el comando set. La sintaxis es: set Como resultado el intérprete regresará un largo listado de variables de ambiente y locales. También es posible asignar valores a las variables mediante el comando set (Consultar las páginas de man para más información). IMPORTANTE: debe hacerse una mención especial a la variable PATH, que se encarga de guardar la lista de directorios con archivos ejecutables. Si no se especifica el camino exacto de un programa, el sistema busca en los directorios especificados en PATH, siguiendo el orden de izquierda a derecha. El carácter separador de directorios es dos puntos. EJERCICIO 1. Despliega en la consola el contenido de las siguientes variables de entorno: • • • • • $PATH $TERM $PS1 $HOME $BASH Parámetros de posición Los parámetros de posición son variables especiales de BASH que contienen los valores de los parámetros que recibe un script o una función. El número indica la posición de dicho parámetro en la llamada al código. La sintaxis es: Nombre_del_script parametro1 parametro2 El nombre del programa o script que se está ejecutando se denota por la variable $0. Después, el primer parámetro se denota por la variable $1, hasta el noveno que es $9; a partir del décimo parámetro se usa la notación ${Número}. El comando shift desplaza la lista de parámetros hacia la izquierda para procesar los parámetros más cómodamente. M.I. Rosalía Mora Juárez FIE 2010 8 Laboratorio de Herramientas Computacionales EJEMPLO: uso de parámetros de posición y de variables locales: grep "^$1:" /etc/passwd grep ":$GID:" /etc/group | cut -f1 -d: La primera línea muestra al usuario la información contenida en el primer parámetro recibido. La segunda línea presenta el nombre del grupo, cuyo identificador se encuentra en la variable GID. Variables especiales Las variables especiales son aquellas que tienen una sintaxis especial y que hacen referencia a valores internos del proceso. Son las que informan sobre el estado del proceso, y son tratadas y modificadas directamente por el intérprete, por lo tanto, son de sólo lectura. (Los parámetros de posición pueden incluirse en esta categoría). La siguiente tabla describe brevemente estas variables. VARIABLE ESPECIAL DESCRIPCION $$ $* $@ Identificador del proceso (PID). Se usa para asignar nombres de archivos temporales Cadena con el contenido completo de los parámetros recibidos por el programa. Como en el caso anterior, pero trata cada parámetro como una palabra diferente. NOTA: la expresión cat "$@" puede usarse tanto para procesar datos de archivos como de la entrada estándar. Número de parámetros. Código de retorno del último mandato (0=normal, >0=error). Último identificador de proceso ejecutado en segundo plano. Valor del último argumento del comando ejecutado previamente. $# $? $! $_ EJEMPLO La primera columna muestra el código de un script para convertir de minúsculas a mayúsculas. La segunda columna indica cómo puede utilizarse el script mayusculas.sh. #!/bin/bash > mayusculas datos.txt > datos.sal > mayusculas <datos.txt > datos.sal > mayusculas Esto es una prueba de ejecución. ^D Y obtenemos la salida ESTO ES UNA PRUEBA DE EJECUCIÓN # convierte a mayúsculas # usando archivos o la entrada estandar # Uso: mayusculas [ [<]fichero ] cat "$@" | tr 'a-zñáéíóúü' 'A-ZÑÁÉÍÓÚÜ' M.I. Rosalía Mora Juárez FIE 2010 9 Laboratorio de Herramientas Computacionales Asignando valores a las variables El intérprete de comandos permite asignar prácticamente cualquier valor a las variables simplemente especificando el nombre de la variable y el valor que queremos almacenar en esa variable. Ejemplo 1 FRUTA=kiwi Total=358 No es necesario declarar el tipo de variable (caracter o numérica), pero hay que tener cuidado al utilizar valores que contienen espacios, por ejemplo: FRUTA=manzana naranja pera generará el siguiente error: FRUTA=manzana naranja pera bash: naranja: command not found Para poder utilizar espacios en los valores de las variables, se requiere que el valor se encierre entre comillas (“”), así le decimos al shell que la variable va a contener una cadena, esto es: $ FRUTA="manzana naranja pera" Hay que tomar en cuenta además que si no se utiliza el signo $ antes del nombre de la variable, únicamente se presenta el nombre de la variable, más no su contenido. Ejemplo 2 FRUTA=platano echo FRUTA FRUTA Si queremos ver el contenido de la variable FRUTA del ejemplo anterior, lo correcto es: FRUTA=platano echo $FRUTA platano Se puede también asignar el valor de otras variables a una variable. Ejemplo 3 X=hola Y="$X, como estas?" echo $Y hola, como estas? Nota: se puede escapar el caracter $ con la barra (\), como se hacía en las expresiones regulares. M.I. Rosalía Mora Juárez FIE 2010 10 Laboratorio de Herramientas Computacionales EJERCICIO Escribe un script en donde se despliegue el valor de la variable VAR=prueba. Incluye los comandos echo, clear y sleep (toma como base el siguiente texto) #!/bin/bash # Variables prueba 1 VAR1=prueba Entrada y salida de datos en scripts de shell Hasta este momento hemos realizado scripts de shell sencillos, pero en ninguno pedimos datos por parte del usuario. Para solicitar datos a un usuario (introducir datos) existe el comando read. La sintaxis general del comando read es: read lista_de_variables En donde lista_de_variables es una o más variables en donde se almacena la información, estas variables deberán de estar separadas por espacios. El comando read espera entrada de datos de la entrada estandar (stdin) y almacena los valores introducidos en las variables o variable especificada. Ejemplo1 read a 10 escribimos el número 10 y presionamos la tecla enter Cuando ejecutamos el comando read, el interprete de comandos queda en espera de que por la entrada estandar se introduzcan datos. En este caso el dato es el número 10, y éste se almacenará en la variable llamada a. También podemos pedir múltiples valores para múltiples variables. Ejemplo 2 $ 5 $ 5 $ 3 $ 2 read a b c 3 2 echo $a escribimos los números 5, 3 y 2 y presionamos la tecla enter echo $b echo $c M.I. Rosalía Mora Juárez FIE 2010 11 Laboratorio de Herramientas Computacionales Pero si solo introducimos un valor: $ read 10 $ echo 10 $ echo $ echo $ a b c $a escribimos el número 10 y presionamos la tecla enter $b $c No se almacenan valores en las variables b y c debido a que no hay datos para introducir. Ahora, tomemos todo lo anterior y hagamos un script: #!/bin/bash echo "Introduzca un valor numerico : \c" read valor echo "El valor que se introdujo fue $valor" y al ejecutarlo: Introduzca un valor numerico: 10 El valor que se introdujo fue 10 escribimos el número 10 y presionamos la tecla enter Como se puede observar en todos los ejemplos anteriores, la escritura en la salida estándar (stdout) la hacemos con el comando echo. Cabe mencionar ahora, algunas de las opciones para echo que podemos incluir en los scripts de Shell para la salida estándar: –m –e – \a – \b – \c – \f – \n – \r – \t – \v No se escribe el caracter de fin de línea Habilita la interpretación de caracteres especiales. IMPORTANTE: para que funcione esta opción la cadena a visualizar debe estar entre comillas dobles (“ ”) Alerta sonora (bell) Retroceso Suprime el caracter de nueva línea Alimentación de hoja (útil cuando se envía a la impresora) Retorno de carro y avance a nueva línea Retorno de carro Tabulador horizontal Tabulador vertical En resumen La lectura de la entrada estándar se puede hacer de dos formas: • Mediante línea de comandos, usando parámetros. • Interactivamente, con el comando read: La salida estándar la trabajamos con el comando echo. M.I. Rosalía Mora Juárez FIE 2010 12 Laboratorio de Herramientas Computacionales Variables en arreglos Un arreglo es un conjunto de valores asignados a un solo nombre de variable. Para acceder a alguno de los valores, se utiliza un número que sirve como índice para los datos. Digamos que deseamos almacenar todos los nombres de frutas en una sola variable a la que llamaremos FRUTA. Si ejecutamos: FRUTA=manzana FRUTA=pera FRUTA=naranja El problema es que la variable FRUTA contendrá únicamente el último valor asignado (naranja en este caso) y no todos los valores. Una variable de tipo arreglo formaliza este tipo de agrupación de valores usando un nombre de variable en conjunto con un numero para acceder los valores, este número es llamado índice. El método más simple para crear un arreglo es asignar un valor a uno de sus índices, esto es expresado de la siguiente manera: nombre[indice]=valor En donde nombre es el nombre del arreglo, index es el índice a la celda que se desea asignar y valor es el valor a asignar. $ FRUTA[0]=manzana $ FRUTA[1]=pera $ FRUTA[2]=naranja IMPORTANTE: en bash, el valor de índice comienza con cero cuando se utilizan valores numéricos. El valor de índice no necesariamente tiene que ser un valor numérico, también se pueden asignar valores de índice que representen datos alfanuméricos, por ejemplo: FRUTA[primera]=manzana FRUTA[segunda]=pera FRUTA[tercera]=naranja También es permitido asignar valores a un arreglo especificando dichos valores entre paréntesis, por ejemplo: FRUTA=(manzana pera naranja) y es equivalente a escribir: FRUTA[0]=manzana FRUTA[1]=pera FRUTA[2]=naranja M.I. Rosalía Mora Juárez FIE 2010 13 Laboratorio de Herramientas Computacionales Si deseamos asignar algún valor que contenga espacios en un elemento del arreglo, tenemos que encerrarlo entre comillas de igual manera que si fuera una variable común y corriente: FRUTA[100]=uvas verdes bash: verdes: command not found lo correcto es: FRUTA[100]="uvas verdes" o bien, podríamos escribir: FRUTA=(manzana pera naranja "uvas verdes" "uvas rojas") Accediendo a valores de variables de tipo arreglo Después de que se ha asignado un valor a una variable de tipo arreglo, se puede acceder a estos valores de la siguiente manera: ${nombre[indice]} donde nombre indice Indica el nombre del arreglo. Es el índice del elemento que al que deseamos acceder. Por ejemplo: FRUTA[0]=manzana FRUTA[1]=platano echo $FRUTA[0] manzana echo $FRUTA[1] platano FRUTA[rara]=kiwi echo $FRUTA[rara] kiwi M.I. Rosalía Mora Juárez FIE 2010 14 Laboratorio de Herramientas Computacionales Variables no modificables ( variables de solo lectura). Para asegurarse que el valor de una variable no sea modificado, se puede indicar como variable de solo lectura con el comando readonly de la siguiente manera: readonly variable EJEMPLO X=1 readonly X X=2 bash: X: readonly variable echo $X 1 M.I. Rosalía Mora Juárez Este es el mensaje que vemos en la terminal FIE 2010 15 Laboratorio de Herramientas Computacionales Expresiones. El intérprete BASH permite utilizar una gran variedad de expresiones en el desarrollo de programas y en la línea de mandatos. Las distintas expresiones soportadas por el intérprete pueden englobarse en las siguientes categorías: • Expresiones aritméticas: las que dan como resultado un número entero o binario. • Expresiones condicionales: utilizadas por mandatos internos de BASH para su evaluar indicando si ésta es cierta o falsa. • Expresiones de cadenas: aquellas que tratan cadenas de caracteres. Las expresiones complejas cuentan con varios parámetros y operadores, se evalúan de izquierda a derecha. Sin embargo, si una operación está encerrada entre paréntesis se considera de mayor prioridad y se ejecuta antes. A modo de resumen, la siguiente tabla presenta los operadores utilizados en los distintos tipos de expresiones BASH. Operadores aritméticos: Operadores de comparación: Operadores lógicos: Operadores binarios: Operadores de asignación: Operadores de tipos de ficheros: Operadores de permisos: Operadores de fechas: Operadores de cadenas: + - * / % ++ -== != < <= > >= -eq –nt –lt -le –gt –ge ! && || & | ^ << >> = *= /= %= += -= <<= >>= &= ^= |= -e –b –c –d –f -h -L -p -S –t -r -w -x -g -u -k -O -G –N -nt –ot –et -z -n Expansión aritmética El Shell provee un mecanismo para realizar aritmética de enteros básica llamado expansión aritmética. La expansión aritmética está basada en un estándar POSIX1, así que es posible encontrar esta característica en la mayoría de los shells modernos. El formato para la expansión aritmética es: (( expresión )) donde: expresion 1 Es cualquier expresión matemática que puede usar variables de Shell (que contengan valores numéricos), operadores y/o valores numéricos específicos. POSIX es el acrónimo de Portable Operating System Interface. Tomado de http://es.wikipedia.org/wiki/POSIX M.I. Rosalía Mora Juárez FIE 2010 16 Laboratorio de Herramientas Computacionales La expansión aritmética proporciona una potente herramienta para realizar operaciones aritméticas y expresiones sobre cadenas. Para traducir una cadena en una expresión numérica se utilizan los acentos, los paréntesis dobles y el comando let EJEMPLOS La expansión aritmética se puede comprobar en una secuencias de comandos directamente en la terminal: 1. Expansión aritmética usando acento simple en unión con el comando expr . El comando expr hace posible la expansión, para sumar 3 a la variable z z=`expr $z + 3` echo $z +3 2. Expansión aritmética con paréntesis dobles: (…) y $(...). z=$(($z+3)) echo $z 3 Evalúa la expresión dentro de (( )) z=$((z+3)) echo $z 3 Otra manera de realizar una expresión aritmética También se pueden realizar expresiones aritméticas (operaciones) con paréntesis doble y sin $. z=0 (( z += 1 )) Ahora vamos a incrementar z en 1. PERO Cuidado! escribir (( $n += 1 )) es incorrecto echo "El resultado es= $z" El resultado es =1 3. Expansión aritmética con paréntesis dobles y el uso de let Los acentos permiten usar espacios en la asignación de variables. El operador let permite la evaluación aritmética más allá de la expansión. let z=z+3 echo $z 3 o también se puede escribir entre comillas dobles: let "z += 3" echo $z 3 M.I. Rosalía Mora Juárez FIE 2010 17 Laboratorio de Herramientas Computacionales En relación a los operadores <, >, <= y >=, ésto se expresan generalmente entre paréntesis dobles. Por ejemplo: (("$a" < "$b")) (("$a" <= "$b")) (("$a" > "$b")) (("$a" >= "$b")) Comando expr El comando expr recibe números y operadores aritméticos como argumentos, efectúa los cálculos indicados y devuelve el resultado. El comando expr usa la convención de C para cierto y falso: 0 es falso, y distinto de 0 es cierto. La sintaxis para el comando expr es: expr <argumento1> operacion <argumento2> donde: argumento1 operacion argumento2 Argumento para realizar una operación. Operador que realiza las operaciones suma (+), resta (-), multiplicación (*), división entera (/), resto de división entera (%). Argumento para realizar una operación. IMPORTANTE: • Argumentos y operaciones deben estar separado por espacios en blanco. • expr se efectua sólo con números enteros. • Los símbolos * y / deben ser escapados escribiendo \* y \/, al igual que los paréntesis, que deben escribirse como \( y \). Si no se pone \, el bash no interpreta el * como operador para la multiplicación, sino como un metacaracer (expandir una expresión regular). EJEMPLOS expr 4 + 5 9 devuelve la suma de 4+5=9 expr 3 \* 4 + 6 \/ 2 15 devuelve la solución de la expresión aritmética 3*4 + 6/2 = 15 expr 3 \* \( 4 + 3 \) \/ 2 10 devuelve la solución de la expresión aritmética 3*(4+3) /2 = 10 M.I. Rosalía Mora Juárez FIE 2010 18 Laboratorio de Herramientas Computacionales El comando expr realiza también operaciones lógicas de comparación, aceptando los operadores =, !=, >, <, >= y <=. El operador != indica es "no es igual a"; ya que el ! se usa para negar. IMPORTANTE: los caracteres =, !=, >, <, >= y <= también requieren ser escapados anteponiendo \. EJEMPLOS expr 6 \< 10 devuelve 1, cierto para expr expr 6 \> 10 devuelve 0, falso para expr devuelve 1, cierto para expr expr abc \< abd y = ´expr $ y + 1´ Incrementa la variable y, con el mismo efecto que permiten y=y+1 o bien y=$(($y+1)). Comando test El comando test prueba condiciones y devuelve valor cierto (0) o falso (distinto de 0) según el criterio de cierto y falso del Shell (esto lo hace apto para usar en la estructura condicional if). La sintaxis para test tiene dos formas equivalentes: test expresion [ expresion ] expresion puede ser una evaluación de: • Cadena de caracteres: -z CADENA -m CADENA CADENA1 = CADENA2 CADENA1 != CADENA2 CADENA CADENA1 < CADENA2 Verdadero si la longitud de la cadena es cero Verdadero si la longitud de la cadena es distinta de cero Verdadero si las cadenas son iguales Verdadero si las cadenas son distintas Verdadero si la cadena no es nula es menor, en orden alfabético de ASCII IMPORTANTE: se debe tener en cuenta que símbolos como "<" deben ser escapado dentro de una construcción que utilice []. • Enteros: INT1 INT1 INT1 INT1 INT1 INT1 M.I. Rosalía Mora Juárez -eq INT2 -ne INT2 -gl INT2 -lt INT2 -ge INT2 -le INT2 verdadero si verdadero si verdadero si verdadero si verdadero si verdadero si FIE 2010 INT1=INT2 INT1!=INT2 INT1 > INT2 INT1 < INT2 INT1 >= INT2 INT1 <= INT2 19 Laboratorio de Herramientas Computacionales • Archivos: suponiendo que ARCHIVO contiene el path y el nombre de un archivo: -s ARCHIVO verdadero si existe ARCHIVO y es un dispositivo de bloques verdadero si existe ARCHIVO y es un dispositivo de caracteres verdadero si existe ARCHIVO y es un directorio verdadero si existe ARCHIVO verdadero si existe ARCHIVO y tiene permisos de lectura Verdadero si existe ARCHIVO y tiene tamaño mayor que 0 -w ARCHIVO -x ARCHIVO verdadero si existe ARCHIVO y tiene permisos de escritura verdadero si existe ARCHIVO y tiene permisos de ejecución -b ARCHIVO -c ARCHIVO -d ARCHIVO -e ARCHIVO -r ARCHIVO • Expresión Lógica: si EXP1 y EXP2 contienen expresiones lógicas: !EXP EXP1 -a EXP2 EXP1 -o EXP2 Negación Y lógico o AND O lógico o OR -a y –o son similares a los operadores de comparación de bash && (AND) y || (OR), respetivamente, y se utilizan generalmente dentro de los corchetes dobles. [[ condicion1 && condicion2 ]] EJEMPLOS 1. test devuelve cierto ante una cadena no vacía, y falso ante una cadena vacía: if test "cadena" ; then echo Cierto ; else echo Falso; fi if test "" ; then echo Cierto ; else echo Falso ; fi if [ cadena ] ; then echo Cierto ; else echo Falso; fi if [ ] ; then echo Cierto ; else echo Falso ; fi 2. test prueba una cantidad de condiciones y situaciones según la opción elegida: if [ -f archivo ]; then echo "Existe archivo"; \ else echo "No existe archivo" fi Aquí la condición [ -f archivo ] es cierta si archivo existe y es un archivo normal. Otras opciones que podemos utilizar en lugar de –f son: -r -w -x -d -s comprueba si es posible leer el archivo. comprueba si se puede escribir en él. comprueba si es un archivo ejecutable. si es un directorio. si tiene tamaño mayor que 0. M.I. Rosalía Mora Juárez FIE 2010 20 Laboratorio de Herramientas Computacionales 3. Se comparan cadenas de caracteres: = para igualdad y != para desigualdad. Algunos ejemplos son: [ $DIR = $HOME ] [ $LOGNAME = "usuario1" ] [ $RESULTADO != "error" ] 4. Cuando La condición siguiente devuelve falso si la variable no está definida. [ "$VAR1" ] Las comillas dan la cadena nula cuando VAR1 no está definida; sin comillas no habría cadena y daría error de sintaxis. 5. La condición –eq compara igualdad de expresiones que resultan en un número. [ expresion_numerica1 -eq expresion_numerica2 ] 6. El comando test se usa generalmente para determinar si un comando se completó con éxito, en cuyo caso el valor de retorno es 0. El siguiente script crea un archivo si no existe. #! bin/bash # nuevo_arch.sh # Recibe un nombre y crea un archivo con ese mismo nombre; # si ya existe emite un mensaje de que ya fue creado if [ -f $1 ] then echo El archivo $1 ya existe else touch $1 echo Fue creado el archivo $1 fi echo echo fin NOTA: el comando touch crea archivos vacios. Para comprobar su acción, podemos ejecutar el script de la siguiente forma: sh nvoarch.sh nuevo1 ls -l nuevo1 M.I. Rosalía Mora Juárez FIE 2010 21 Laboratorio de Herramientas Computacionales 7. Otros operadores aceptados por test son -a (AND) y -o (OR). #! bin/bash # permisos_arch.sh # indica si un archivo tiene permiso de lectura y escritura ARCH=$1 if [ -r $ARCH -a -w $ARCH ] then echo El archivo $ARCH se puede leer y escribir else echo Al archivo $ARCH le falta algún permiso fi ls -l $ARCH echo fin 8. Cont test también se pueden utilizar los operadores para cadenas: #! bin/bash # cadena_nula.sh # indica si una cadena es de longitud cero, o sea vacia clear CADENA='' #Si ponemos un espacio la cadena ya no sera nula if [ -z "$CADENA" ] then echo "\$CADENA esta vacia." else echo "\$CADENA no esta vacia." fi echo fin M.I. Rosalía Mora Juárez FIE 2010 22