Página siguiente Página anterior Índice general

3. Variables

Como en los lenguajes de programación corrientes, en la programación en shell existen las variables, que son nombres simbólicos para zonas de memoria que almacenan datos que nos interesan. Pero al contrario que los lenguajes de alto nivel normales, las variables de los guiones no tienen tipo, o quizás sería más apropiado decir que tienen un tipo único y permanente: a todos los efectos se tratan como ristras de caracteres.

Para poder hacer sumas y restas hay una orden especial, la orden expr. Esta orden tiene que recibir cada número u operando como un parámetro independiente, así que devolverá un error si intentas hacer algo como expr 5+7. No vale la pena extenderse aquí, aunque si quieres más información sobre esta instrucción o cualquier otra característica de la programación en shell, ya sabes adonde acudir.

3.1 Referenciar variables

Las variables de los guiones no se declaran, y siempre están inicializadas con una ristra vacía o nula. Nótese que esto no es lo mismo que contener un espacio. Una ristra vacía o nula es una ristra que no contiene ningún caracter.

Hay que tener cuidado al asignar valores a las variables, ya que no se debe dejar ningún espacio entre el signo de asignación (el `=') y la variable o el valor asignado (algo que, por otra parte, es una muy buena costumbre cuando da igual).

Para referirse a las variables, hay que utilizar el signo dólar ($) antes del nombre de ésta, siempre que nos refiramos a ellas para consultar su valor (si asignamos un valor a la variable, o utilizamos la orden read, que escribe en ella, NO hay que poner el signo de dólar). Si nos olvidamos del signo dólar, y hacemos algo parecido a:

        y=hola
        x=y

Nos encontraremos con la desagradable sorpresa de que el valor de x es el carácter y, y no los caracteres hola, como quizás pretendiéramos. Para hacer la asignación correctamente, tendríamos que haber escrito:

        y=hola
        x=$y

Como en todas o al menos la mayoría de las cosas en UNIX, los nombres son case sensitive, es decir, que no es lo mismo y que Y (¡aviso para los programadores acostumbrados al MS-DOS!).

3.2 ¿Cómo funciona el analizador del intérprete?

Es útil saber el funcionamiento del analizador sintáctico (parser) del intérprete de órdenes a la hora de programar. Al fin y al cabo, significa saber cómo va a interpretar nuestras órdenes.

Como la mayoría de los analizadores de los lenguajes interpretados, primero realiza algunas sustituciones, al leer la orden, y luego ejecuta la orden que le queda después de las sustituciones.

Las sustituciones hechas por el intérprete de órdenes de UNIX son sustituciones de comillas y sustituciones de variables (lo que vea con un signo dólar que no esté ``escapado''). Según el intérprete en particular, hará algunas sustituciones más, como sustituciones del caracter ~ (que indica el directorio raíz del usuario), los caracteres {}, los caracteres [], etc.

Las sustituciones de variables son lo que más nos interesa. Cuando el analizador se encuentra un singo de dólar, que no tenga antes una barra invertida (\), lo interpreta como una variable. Lo que hace, entonces, es avanzar hasta que tiene el nombre completo de la variable, y cuando lo tiene, sustituye el dólar y el nombre por el valor de la variable. Si no existe ninguna variable que tenga ese nombre, no es un error. Simplemente lo sustituye por nada. Este comportamiento puede acarrear algunos fallos difíciles de descubrir. Por ejemplo, al procesar la línea

        mensaje="$foo y alguna otra cosa"

El analizador dectecta el signo $, que indica variable, avanza hasta que tiene completo el nombre de la variable (el nombre es, por supuesto foo), y sustituye la ristra $foo por el contenido de la variable en cuestión. Es importante tener esto en cuenta, porque si quisiésemos poner bar después del contenido de la variable $foo, no podríamos escribir $foobar, porque el analizador creería que estaríamos consultando la variable foobar. Lo que tenemos que hacer es ``delimitar'' el nombre de la variable con llaves, quedando ${foo}bar.

3.3 Dos órdenes útiles: echo y read

Dos órdenes bastante útiles para probar algunas estupideces con variables son echo y read. La primera es como su homónimo de MS-DOS (o mejor dicho: el de MS-DOS es una copia, probablemente peor, de su homónimo UNIX), para mostrar texto por pantalla, y la segunda, como su nombre indica, es para leer del teclado y poner el resultado en una o varias variables. El funcionamiento de read es el siguiente: lee del teclado una ristra, y va asignando las palabras en orden a cada una de las variables que se le pasen como parámetros, asignando el resto de la ristra a la última variable. Es decir, que si se le pasan tres variables como parámetro, se asigna la primera palabra a la primera variable, la segunda a la segunda variable, y el resto de la ristra leída a la tercera variable. Por ejemplo:

        $ read foo bar
        Escribo demasiadas palabras
        $ echo $foo
        Escribo
        $ echo $bar
        demasiadas palabras

3.4 Parámetros

Los parámetros son variables normales, que tienen los nombres $1, $2 ... $9. Aunque se pueden dar más de nueve parámetros a un guión para el intérprete de órdenes, sólo se puede acceder de forma directa a los nueve primeros. La orden shift permite desplazar los parámetros de sitio, de tal forma que sean accesibles los que estén más allá del noveno, con el inconveniente de no poder acceder a los primeros. En realidad, en el Korn shell (y en bash) se puede acceder al resto de los parámetros directamente con la construcción ${número}. El funcionamiento de shift es el siguiente:

Supongamos que tenemos como parámetros $1=-o, $2=foo y bar, por llamar al guión (suponiendo que el nombre del guión es compila) así:

        compila -o foo bar

Lo que queremos es quitarnos de enmedio las opciones, después de haberlas procesado, de tal forma que el tercer parámetro (bar) se quede como primero. Lo que haremos, entonces, es llamar dos veces a shift, o llamar a shift con el parámetro 2. Teniendo este código:

        shift 2
        echo $1

Y suponiendo la llamada anterior, el resultado por pantalla sería bar.

Las variables $#, $*, $0 nos permiten saber el número de parámetros pasados al guión, la ristra entera de todos los parámetros pasados, y el nombre del programa que se ha llamado. Esto último puede parecer estúpido, pero piensa que en UNIX pueden hacerse enlaces a ficheros. Si utilizas Linux, cuando llamas al vi en realidad estás ejecutando el fichero ejecutable vim. Fíjate cuando hagas un ls -l en tu directorio /usr/bin. Tendrá que salir un fichero parecido a este:

        rwxr-xr-x root     root     vi->vim

Eso significa que el fichero vi no es un ejecutable, sino un enlace que apunta al fichero vim del mismo directorio. Así, por ejemplo, hay un caso parecido con awk, que apunta a gawk. Cuando llamas a cualquiera de los dos programas sin parámetros, te da la ayuda, diciéndote cada uno de ellos que se llama con el nombre con el que tú le hayas llamado (con esto no quiero decir que el awk/gawk sea un guión, por supuesto, pero los lenguajes de alto nivel tienen una opción parecida).

3.5 Valores devueltos. Orden exit

Los valores devueltos por los programas, por convenio, son 0 si el programa ha ido perfectamente (cero porque es el código de error), y un número distinto de cero, normalmente 1 o -1 para indicar algún tipo de error. Es de notar que cuando ejecutemos un pipe, el valor devuelto por el pipe será el del programa que se ejecutó en último lugar.

Esto nos sirve para dos cosas: primero, para saber por qué preguntar cuando chequeemos el valor devuelto por un programa. Y segundo, para devolver los valores establecidos por convenio cuando salgamos de nuestros programas (ya sea hechos con lenguajes de alto nivel o guiones).

La forma de devolver valores al salir del programa es darlos como parámetro a la orden exit. Si lo hacemos sin parámetros, se devolverá un cero.

3.6 Asignación de caracteres especiales

Por último, un apunte sobre asignar caracteres especiales para el intérprete a variables: cuando nosotros asignamos algo a una variable, se asigna tal cual nosotros lo vemos en la pantalla (cuando son caracteres especiales), y la sustitución se hace cuando la utilicemos en alguna expresión, si entra dentro de una orden. Veamos el siguiente ejemplo como aclaración de lo dicho.

        cd /
        asterisco=*.txt
        cd /home/zoso/cambio
        ls $asterisco

Si ejecutamos el siguiente código, la salida de éste será la lista de ficheros que concuerdan con la expresión regular almacenada en la variable asterisco, pero los que se encuentren en el directorio /home/zoso/cambio, no los que se encuentren en el directorio raíz.


Página siguiente Página anterior Índice general