|
|
Home / Teaching / Telecommunication Engineering / Computer Architecture
Laboratory / Laboratory 1 |
|
|
|
|
|
|
|
|
Laboratorio de Arquitectura de Ordenadores |
|||||||||||||||
|
|
||||||||||||||
|
Este primer laboratorio está diseñado para que el alumnos adquiera una comprensión general de la programación en shell script. Esto incluye el manejo de variables y el uso de otras estructuras como decisiones y bucles. El tutorial presenta una cierta cantidad de ejemplos fáciles de seguir para ilustrar cada aspecto de la programación. Se trata de proporcionar un enfoque conciso y práctico que complemente las clases teóricas, en lugar de repetir los contenidos de éstas. Se han incluido una buena cantidad de hipervínculos para que el alumno tenga la posibilidad de aumentar sus conocimientos. Tras completar este tutorial, el alumno estará familiariazado con los principios básicos de la programación en Shell Script, tendrá una visión clara de su potencial y, en consecuencia, será capaz de afrontar el ejercicio propuesto al final. |
|
Como ya sabe, las variables en los scripts tienen un nombre que se establece al inicializarlas (var_nombre=valor, siempre sin espacios entremedias), y se referencian utilizando el carácter especial '$', preferiblemente entre llaves (${var_nombre}). Esto es de utilidad para el intérprete del script, que así sabe que la variable ya tiene un valor. En esencia, 'var_nombre' representa el nombre de la variable, mientras que $var_nombre o ${var_nombre} representa su valor. Es muy importante recordar este último punto, puesto que omitir alguno de estos caracteres especiales puede llevar a errores bastante difíciles de detectar, dados los mensajes de error poco útiles que suele dar el intérprete.. Veamos un ejemplo básico de creación y manejo de una variable, en concreto la impresión de su valor por pantalla: |
|
|
|
|
Ejemplo 1 Aunque este es probablemente el ejemplo más simple, merece la pena comentar ciertas características comunes a todos los scripts:
Naturalmente, una variable puede tomar cualquier valor, incluyendo valores numéricos. No obstante, todas son tratadas como cadenas a no ser que se especifique lo contrario, como veremos en los próximos apartados. Puede ver más ejemplos aquí. |
|
|
Una de las virtudes de los shell scripts de Linux radica en la potencia del tratamiento de cadenas que ofrece. Como ya hemos comentado, las variables se consideran cadenas a no ser que se especifique de otra manera, de modo que todas se pueden tratar tal y como se describe en este apartado. Puede consultar las transparencias de las clases teóricas para revisar los operadores que permiten comprobar si una variable está definida, la extracción de una subcadena y la extracción de patrones de varias formas. Este ejemplo incluye los operadores más útiles. ¿Puede determinar cual será la salida sin ejecutar el script? |
|
|
|
|
Ejemplo 2 Preste atención al uso de comillas simples ('') para delimitar la asignación de cadenas con más de una palabra. Esto es necesario para hacer saber al intérprete que no estamos utilizando una serie de comandos, sino que estamos inicializando una variable con varias palabras. Podríamos haber utilizado comillas dobles, que son menos estrictas, lo que puede llegar a ser útil para incluir ciertos caracteres especiales. Haga click aqui para obtener más información sobre éste y otros asuntos relacionados con el entrecomillado Para obtener una guía completa de todas las posibilidad existentes para manejar cadenas, con abundancia de ejemplos, haga click aqui. ¿Y qué pasa cuando quiere utilizar una variable como un número en vez de como una cadena? En ese caso es necesario indicárselo al intérprete, de forma que pueda realizar las operaciones numéricas deseadas. El siguiente ejemplo muestra el funcionamiento básico. Como antes, es un buen ejercicio intentar predecir el resultado de la ejecución del script. |
|
|
|
|
Ejemplo 3 Se utiliza $(('expresion')) para especificar que 'expresion' debe ser interpretada como una expresión aritmética, no como una cadena o el nombre de una variable.Otra posibilidad es utilizar el comando 'expr', aunque se suele preferir la primera construcción. Es importante recordar que solo se pueden realizar operaciones sobre números enteros. Números no enteros (por ejemplo, '2.2') son considerados siempre como cadenas. Puede encontrar más información y ejemplos sobre el manejo de expresiones aritméticas aquí. |
|
|
Otra de las razones de la potencia de la programación en shell script es la capacidad de control de flujo que ofrece. La herramienta más importante es la construcción if/else, que se puede usar de forma similar a como se hace en otros lenguajes de programación que ya conoce. Su estructura es la siguiente:
|
|
|
|
|
Estructura 1 Una condición se especifica entre corchetes, y puede incluir comparaciones de cadenas, operadores de archivo (por ejemplo, para saber si un archivo existe), operaciones lógicas (and/or lógico) y operadores aritméticos (igual que, mayor que, etc. para cadenas que se interpretan como números). Para una lista completa de todos los operadores posibles, revise las transparencias de la clase teórica, o haga click aquí para una lista más detallada, con un gran número de ejemplos.El siguiente ejemplo muestra una utilización básico pero muy común de esta construcción, pidiendo al usuario que realice una elección y ejecutando un código u otro en función de esa elección:
|
|
|
|
|
Ejemplo 4 El siguiente ejemplo utiliza operadores de archivo para comprobar si un archivo existe y si el usuario tiene permiso de escritura en él. El nombre del archivo se pasa como el primer parámetro al ejecutar el script desde la línea de comandos, tal y como veremos en el apartado 8. Cabe destacar como las dos condiciones se asocian mediante el operador and (%%): el codigo se ejecutará solo su ambas condiciones se satisfacen.
|
|
|
|
|
Ejemplo 5 Estos ejemplos muestran un uso básico de la estructura if/then/else. Puede encontrar ejemplos más complejos aquí, incluyendo el uso de otros operadores y el de condiciones if/then/else anidados. |
|
|
Aunque la construcción if/else es lo suficientemente potemte como para cubrir todas las necesidades en cuanto a control de flujo, en algunos casos su uso exclusivo produce scripts demasiado complejos, con demasiadas condiciones y/o if/else anidados que hacen difícil de leer el código. Hay dos construcciones que permiten salvar tiempo y espacio cuando esto sucede: 'case' y 'select'. La primera es útil para elegir un cierto código a ejecutar de entre varias posibilidades en función del valor de una variable, sin tener que recurrir a una construcción if/else con varias cláusulas 'elif'. La segunda presenta al usuario un menú por pantalla para que elija entre las opciones disponibles, de forma que ahorra un buen número de líneas en el script. La construcción 'case' tiene la siguiente estructura, donde 'expresion' es una variable o una expresión compuesta de varias variables que puede tomar valores entre patron1 y patronN:
|
|
|
|
|
Estructura 2 El siguiente ejemplo muestra una calculadora a la que se le pasan los datos y la operación a realizar por línea de comandos (puede acudir al material de la clase teórica o al apartado 8 para revisar este tipo de paso de parámetros) La calculadora se basa en una construcción case que realiza una u otra operación numérica con los dos primeros parámetros en función del valor del tercero. Cabe destacar el uso del patrón 'por defecto' (*), que representa cualquier posibilidad no contemplada anteriormente.
|
|
|
|
|
Ejemplo 6 La construcción 'select' resulta muy útil cuando el usuario ha de elegir un elemento de una lista, puesto que presenta automáticamente un menú ya formateado que lee la selección del usuario en la variable especificada, como se muestra en el cuadro. Es necesario especificar el caracter que delimita los elementos de la lista. Además, hay que indicar una pregunta con la que se pedirá al usuario que realice una elección, como se muestra en el ejemplo más abajo. El uso típico de esta construcción incluye en su interior un select que efectúa una o utra acción en función de la elección del usuario.En resumen, 'select' asigna un valor a una variable de acuerdo a la elección del usuario, mientras que 'case' realiza una acción elegida entre varias posibles dependiendo del valor de una variabls. Es evidente que ambas construcciones son complementarias en multitud de situaciones.
|
|
|
|
|
Estructura 3 El ejemplo presentado a continuación constituye un uso típico de la construcción select. Permite al usuario elegir entre cuatro elementos, mostrando un menú con formato, y realiza la acción correspondiente al elemento elegido mediante una construcción case. Estas acciones consisten simplemente en la llamada a un comando, pero puede imaginar lo útil que esto resulta para realizar tareas mas complejas, ya que la estructura del código será siempre la misma.
|
|
|
|
|
Ejemplo 7 Puede encontrar más ejemplos sobre las construcciones case y select aquí |
|
|
Los bucles son otra de las herramientas imprescindibles en programación estructurada. Como ya sabe, su objetivo es repetir un cierto código un número de veces que depende de una condición. El bucle más básico es la construcción 'for', en el que el número de iteraciones es conocido antes de ejecutar el bucle. Su estructura se muestra a continuación. El código se repite tantas veces como elementos haya en la lista (que tendrá el mismo formato que en para la construcción select), y la variable tomará el siguiente valor de la lista cada vez, comenzando por el primero.
|
|
|
|
|
Estructura 4 El sencillo ejemplo que se muestra a continuación muestra los cuadrado de los diez primeros números. Recuerde que es necesario especificar un delimitador al utilizar la lista, es decir, hay que dar un valo a la variable interna IFS. Puede encontrar más información sobre variables internas aquí.
|
|
|
|
|
Ejemplo 8 Este tipo de bucles ofrecen un gran número de posibilidades, puede consultar más ejemplos aquí. |
|
|
Aunque los bucles for son muy útiles y se usan con mucha frecuencia, en ciertas ocasiones no son la mejor opción, puesto que el número de iteraciones no se conoce antes de la ejecución del bucle, sino que depende de otra condición. En ese caso, es necesario utilizar un bucle 'while'. Cualquier bucle for puede ser sustituido por un bucle while equivalente. La estructura de éste se muestra a continuación. El código es ejecutado indefinidamente hasta que la condición entre corchetes. El formato y la interpretación de estas condiciones es igual que en el caso de las construcciones if/else.
|
|
|
|
|
Estructura 5 El siguiente ejemplo imprime todos los números de la secuencia Fibonacci menores que 100. Esta secuencia se caracteriza porque un elemento de ella es la suma de los dos elementos anteriores, comenzando por 1 (1,1,2,3,5,8,13,...). Observe que este script se podría haber realizado también con un bucle for. |
|
|
|
|
Ejemplo 9 Para consultar más ejemplo de uso de este bucle (incluyendo aquellos casos en los que no se puede encontrar un bucle for equivalente), y aprender sobre el bucle 'until' como posible alternativa en ciertos casos, haga click aquí. |
|
|
Este apartado presenta conceptos y herramientas que van más allá del funcionamiento básico pero son bastante útiles. Comenzaremos con los parámetros posicionales, es decir, parámetros pasados al script por línea de comandos. Si se llama al script mediante "./scriptname param1 param2", el dato param1 será almacenado en la variable $1, y el dato param2 será almacenado en la variable $2. La variable $* almacenará la lista completa de parámetros (incluyendo el nombre del script), y $# almacena el número de elementos en esa lista. Ya hemos realizado un uso básico pero típico de este mecanismo en algunos de los ejemplo anteriores, pero puede encontrar ejemplo más sofisticados aquí. |
|
|
|
|
|
Otra posibilidad muy útil que ofrece la shell es la redirección de la entrada o la salida desde la pantalla a un archivo. El caso de uso típico es la redirección de la salida de un comando a un archivo. Por ejemplo, 'ls > arch' creará un nuevo archivo llamado 'arch' con la salida del comando 'ls'. Si se usa el operador '>>' en lugar de '>', la salida será incluida al final del archivo en el caso de que éste ya existiese. Para la entrada por teclado, los operadores equivalentes son '<' y '<<'. Otra posibilidad es pasar a un comando como entrada la salida de otro, utilizando una tubería (pipe, '|'), el ejemplo típico es 'ls | less'. |
|
|
Finalmente, es habitual llamar a un buen número de comandos desde un script. Para asignar la salida de un comando a una variable, solo es necesario hacer var = $(comando) |
|
|
El siguiente ejemplo ilustra la redirección de entrada y salida (E/S) y el manejo de comandos descrito. Su funcionalidad consiste en extraer el día y la hora manteniendo un registro, consistente en un archivo que contiene todas las fechas en las que se ejecutó el script y otro archivo que sólo contiene la última hora a la que se ejecutó el script.
|
|
|
|
|
Ejemplo 10 Puede encontrar más ejemplos aquí. |
|
|
Para mejorar sus conocimientos sobre programación en shell script, este tutorial es muy apropiado. Tenga en cuenta que esta asignatura solo cubre una pequeña parte de esos contenidos, pero es muy útil utilizarlo como referencia, además de como fuente de ejemplos. Si prefiere un libro en papel, éste está en la biblioteca y proporciona una gran cantidad de ejemplos explicados detalladamente:
Cuando esté programando, este resumen la resultará muy útil. |
|
Este
ejercicio consiste en el desarrollo de un script (proc.sh) que permita
obtener la representación en binario
de números representado en los sistemas Decimal, Octal y Hexadecimal. Es
decir, se tendrán que contemplar las siguientes conversiones:
1.
Decimal
a Binario
2.
Octal
a Binario.
3.
Hexadecimal
a Binario
El modo
comando admite dos parámetros, el primero indicará el sistema de
representación (D, O, H) en que se encuentra el número a convertir
> ./proc.sh sist_representación numero
En modo menú realizará las
mismas operaciones, pero el sistema de representación y el número serán introducidas
por el usuario interactivamente.
Para un mejor desarrollo del script utilice funciones, para realizar cada una de las conversiones. |
Punto de partida |
|
|
|
La ejecución del script en ambos modos debe ser similar a ésta. Para comprobar su solución intente realizar al menos las operaciones mostradas aquí y compruebe los resultados:
Salida por pantalla del script Para corregir su script, se realizarán un cierto número de pruebas similares a las anteriores. |
|
|
© Ralf
Seepold -
last updated 23/02/2006 |
|
Location | Personnel | Teaching | Research | News | Intranet |
|
|