3.5. Comandos del shell

Un comando puede ser clasificado en las siguientes tipos de comandos (de menor a mayor nivel):

  1. Comandos simples

  2. Tuberías

  3. Listas AND-OR

  4. Listas

  5. Listas compuestas

  6. Comandos compuestos (o estructuras de control)

  7. Definiciones de función

Cada uno de estos tipos se forma mediante la composición de elementos de los tipos inferior. Pero también se permite anidar distintos tipos de comandos (no todas las combinaciones son posibles como se verá más adelante), por lo que podríamos encontrarnos: tuberías de comandos compuestos, comandos compuestos formados por otros comandos compuestos, etc.

En general, el valor devuelto por un comando compuesto (tipo b y superiores) será el valor devuelto por el último comando simple ejecutado.

A continuación describiremos cada uno de los tipos. Puede ver más detalles en el apartado 2.9 del estándar.

3.5.1. Comandos simples

Un comando simple está formado por (todos los elementos son opcionales) una secuencia de asignación de variables y redirecciones (en cualquier orden) seguida de palabras (elemento ejecutable y sus argumentos) y redirecciones. A continuación se muestra la estructura genérica de un comando simple (los corchetes [ ] indican qué elementos son opcionales, que es la notación usada en el resto de este documento):

[VAR=v] [redir] [ejecutable args] [redir]

Pudiendo ser el ejecutable programas «ejecutables» (comandos internos y ejecutables externos) e «interpretables» (funciones).

Es decir, en un mismo comando simple se puede hacer simultáneamente la asignación de variables y la ejecución de un programa. Cuando un comando simple no incluye un programa a ejecutar, la asignación de variables afecta a todo el shell, de lo contrario la asignación sólo afecta al programa que se va a ejecutar.

Si en un mismo comando simple hubiera que hacer expansiones en las palabras y en la asignación de variables, primero se hace las expansiones de las palabras.

Ejemplos de comandos simples:

VAR=x

El anterior comando asigna el valor x a la variable VAR y afecta a todo el proceso shell actual.:

VAR=x programa

Asigna el valor x a la variable VAR y afecta solo al programa.:

VAR=y OTRA=z

VAR=x programa $VAR

echo $VAR

Se asigna el valor y a la variable VAR y el valor z a la variable OTRA, que afectan a todo el shell. A continuación, asigna el valor x a la variable VAR y afecta sólo al programa, al cual se le pasa como primer argumento y. A continuación se imprime y por pantalla.:

VAR=x > fichero programa

VAR=x programa > fichero  #equivalente

Ambas líneas, asignan el valor x a la variable VAR que afecta solo al programa. Se ejecuta el programa y la salida estándar se redirige al archivo fichero. La redirección se realiza independientemente de que aparezca antes o después del programa. Si hubiera varias redirecciones se realizan en el orden de aparición en la línea, de izquierda a derecha.

3.5.2. Tuberías

Una tubería es una secuencia de uno o más comandos (simples o compuestos, pero no ningún tipo de lista) separados por el operador |. La salida estándar de un comando se conecta a la entrada estándar del siguiente comando (cada comando se ejecuta en otro subshell simultáneamente). Esta conexión se hace previamente a cualquier redirección. El formato es:

[ ! ] comando1 [ | comando2 … ]

Opcionalmente, se puede añadir delante el carácter ! que hace la negación lógica del valor devuelto por el último comando, de tal manera que el valor devuelto por la tubería sería 1 si el último comando devuelve 0, o 0 en caso contrario.

3.5.3. Listas AND-OR

Una lista AND es una secuencia de tuberías (tenga en cuenta que una tubería puede ser sólo un comando simple) separadas por el operador &&. El formato es:

tuberia1 [ && tuberia2 … ]

Se van ejecutando las tuberías de izquierda a derecha hasta que una de ellas devuelva un valor distinto de cero. No se realiza ninguna expansión en una tubería hasta que el shell no determine que tiene que ejecutar dicha tubería (dependerá del resultado de la tubería anterior).

Una lista OR es una secuencia de tuberías separadas por el operador ||. El formato es:

tuberia1 [ || tuberia2 … ]

Se van ejecutando las tuberías de izquierda a derecha hasta que una de ellas devuelva un valor cero. No se realiza ninguna expansión en una tubería hasta que el shell no determine que tiene que ejecutar dicha tubería.

Una lista AND-OR es el resultado de combinar listas AND y/o OR en una misma línea. Los operadores && y || se evalúan con la misma prioridad de izquierda a derecha. Ejemplo:

tuberia1 || tuberia2 && tuberia3

3.5.4. Listas

Las listas son secuencias de una o más listas AND-OR separadas por los operadores ; o &. Los operadores ; y & no pueden aparecer seguidos (por ejemplo, daría error prog1 & ; prog2)

Según el operador las listas pueden ser secuenciales, asíncronas o mixtas (combinación de ambas).

3.5.4.1. Listas secuenciales

Se utiliza como separador el operador ;. Se van ejecutando los distintos comandos secuencialmente (no se ejecuta un comando hasta que haya terminado el anterior). Cada lista AND-OR debe estar terminada por el operador ; a excepción de la última donde es opcional. El formato es:

listaAND-OR1 [ ; listaAND-OR2 … ] [ ; ]

3.5.4.2. Listas asíncronas

Se utiliza como separador el operador &. Se van ejecutando los distintos comandos sin esperar a que el comando anterior termine (ejecución en segundo plano). El formato es:

listaAND-OR1 & [ listaAND-OR2 & ]

En este caso, a menos que se haga una redirección explícita de la entrada estándar, si un programa en segundo plano lee de la entrada estándar recibirá un error de fin de fichero (EOF).

3.5.4.3. Listas mixtas

Son combinaciones de listas secuenciales y asíncronas. Por ejemplo:

#asíncrona y secuencial
lANDOR1 & lANDOR2 [ ; ]

#secuencial y asíncrona
lANDOR1 ; lANDOR2 &

#asíncrona y secuencial
lANDOR1 & lANDOR2 & lANDOR3 ; lANDOR4

#secuencial, asíncrona, secuencial
lANDOR1 ; lANDOR2 & lANDOR3

3.5.5. Listas compuestas

No es más que una secuencia de listas (apartado Listas), separadas por el carácter de nueva línea (intro), terminada por el operador ;, el operador &, el carácter de nueva línea (intro) o un comando compuesto. La utilidad de este tipo de listas se verá sobre todo cuando se expliquen los comandos compuestos.

TAREAS

Mire el contenido del script script_operadores.sh, que deberá contener lo siguiente:

script_operadores.sh
#!/bin/sh
head -1 /etc/passwd && echo "Sin error1A" || echo "Con error1B"
head -1 /nofile && echo "Sin error2A" || echo "Con error2B"
echo "Comando dividido \
  en dos líneas"
echo "Sin escapado: $$"
echo "Con escapado: \$\$"
echo "N º de proceso del shell bash:" `pidof bash`

Compruebe que dispone del permiso de ejecución. Invóquelo y analice su funcionamiento.

Desde la línea de comandos, cree listas y tuberías de todos los tipos vistos usando combinaciones de los comandos ls, echo, cat y ps.

3.5.6. Comandos compuestos o estructuras de control

Los comandos compuestos son lo que en otros lenguajes de programación se conocen como estructuras de control. Cada uno de estos comandos compuestos (o estructuras de control) están delimitados por una palabra reservada u operador de control al principio y otro al final (terminador). Si se hace una redirección a continuación del terminador, en la misma línea, esa redirección se aplicará a todos los comandos que se encuentre en ese comando compuesto, a menos que se haga otra redirección explícita en un comando en concreto.

A continuación se hace un repaso por todas las estructuras de control disponibles en el estándar POSIX. Puede consultar el apartado 2.9.4 del estándar para más información.

3.5.6.1. Secuencial (agrupación de comandos)

La agrupación de comandos permite mejorar la legibilidad del código, aplicar una redirección a un conjunto de comandos y crear un subshell entre otras cosas.

Existen dos formas de agrupar comandos, con los siguientes formatos:

  • ( lista-compuesta )

    Se ejecuta la lista compuesta en un subshell. Los cambios que se produzcan en este subshell no afectarán al shell actual. Si la lista compuesta está terminada por el carácter de nueva línea, este carácter puede omitirse.

  • { lista-compuesta }

    Se ejecuta la lista compuesta en el shell actual. Recuerde que las listas compuestas están terminadas por los operadores ;, & o nueva línea (el último comando debe estar separado de la llave de cierre por esos operadores).

En ambos casos, se permite añadir una redirección al final (detrás del ) o }) que afectará a todos los comandos del grupo.

3.5.6.2. Condicional: if-elif-else

Presenta la siguiente sintaxis:

if lista-compuestaA1 then
  lista-compuestaB1
elif lista-compuestaA2 then
  lista-compuestaB2
...
else
  lista-compuestaN
fi

Las entradas elif tienen el significado de un else seguido de un nuevo if. Puede haber tantas entradas elif como se desee. Tanto las entradas elif como la entrada else son opcionales.

En esta estructura, lo primero que se hace es ejecutar la lista-compuestaA1, si el valor devuelto es 0 (ADVERTENCIA: 0 significa verdadero aquí), se ejecutaría lista-compuestaB1 y terminaría la estructura if. Si el valor devuelto no es 0 se comprueba el siguiente elif. Si ninguna de las listas compuestas A devuelve 0 se ejecutaría el bloque del else. En otras palabras, las listas compuestas B solo se ejecutan si se ha comprobado su respectiva lista compuesta A y ha devuelto 0.

A veces, para mejorar la legibilidad, las listas compuestas se encierran entre llaves (agrupación de comandos) pero es opcional. Asimismo, then estará en una línea u otra dependiendo del operador (&, ; o nueva línea) utilizado para terminar la lista compuesta. Si desea dejar una lista compuesta vacía (no quiere realizar ninguna operación en un determinado caso), puede utilizar el comando : (comando nulo).

Por ejemplo, si tenemos un programa llamado condicion que devuelve 0 si algo es verdadero y 1 si es falso, los siguientes ejemplos son equivalentes:

#Ejemplo 1
if condicion; then
  { cmd1; cmd2; }
fi

#Ejemplo 2
if condicion; then
  cmd1; cmd2;
fi

# Ejemplo 3
if condicion
then
  cmd1;
  cmd2;
fi

# Ejemplo 4
if condicion
then
  cmd1
  cmd2
fi

# Ejemplo 5
if condicion; then cmd1; cmd2; fi

# Ejemplo 6
if condicion; then { cmd1; cmd2; } fi

Recuerde que si usa las llaves, debe separarlas del resto de elementos. Por ejemplo:

# Llave inicial no separada de cmd1
if condicion; then {cmd1;  cmd2;} fi

# Llave inicial no separada de 'then'
if condicion; then{ cmd1;  cmd2;} fi

# Llave final no separada de cmd2
if condicion; then { cmd1; cmd2} fi

darán error de sintaxis.

Respecto a la condición que puede usarse, basta cualquier lista compuesta que devuelva un valor (por ejemplo, pueden usarse los comandos internos true o false). El valor de una lista compuesta es el valor del último comando simple ejecutado en la lista compuesta.

Un programa habitual que se utiliza como condición es el programa test. El comando test se puede ejecutar de dos formas (ambas equivalentes):

test expresion

#los [] deben estar separados
[ expression ]

En la segunda forma los corchetes no son operadores ni indican que la expresión sea opcional, sino que realmente son el nombre del programa.

Puede ver la descripción del comando test según el estándar.

Como expresiones más habituales pueden usarse las siguientes:

Expresiones de test para enteros (en los ejemplos n1 y n2 se convierten a enteros)

Expresión

Verdadera sí (devuelve 0)

n1 -eq n2

n1 = n2

n1 -ne n2

n1 ≠ n1

n1 -gt n2

n1 > n2

n1 –ge n2

n1 ≥ n2

n1 -lt n2

n1 < n2

n1 -le n2

n1 ≤ n2

Expresiones de test para cadenas

Expresión

Verdadera sí (devuelve 0)

"$VAR" = "cad"

$VAR vale "cad". Es conveniente, pero no necesario, poner la variable entre comillas por si tuviera espacios o estuviese vacía, para que al expandirse no dé error de sintaxis.

"$VAR" != "cad"

$VAR vale algo distinto de "cad".

-z "$VAR"

"$VAR"

$VAR está vacía. Equivale a "$VAR" = ""

-n "$VAR"

$VAR no está vacía. Equivale a "$VAR" != "" o ! -z

Expresiones de test para ficheros

Expresión

Verdadera sí (devuelve 0)

-e "$FILE"

$FILE existe. Si se indica un enlace simbólico, será cierta sólo si existe el enlace simbólico y el fichero apuntado. Es conveniente que esté entre comillas por el mismo motivo anterior.

-f "$FILE"

$FILE existe y es regular. Si se indica un enlace simbólico, el tipo es el del fichero apuntado.

-h "$FILE"

$FILE existe y es un enlace simbólico

-d "$DIR"

$DIR existe y es un fichero de tipo directorio

-p "$FILE"

$FILE existe y es un fichero especial tubería (pipe)

-b "$FILE"

$FILE existe y es un fichero especial de bloques

-c "$FILE"

$FILE existe y es un fichero especial de caracteres

-r "$FILE"

$FILE existe y puede leerse

-w "$FILE"

$FILE existe y puede modificarse

-x "$FILE"

$FILE existe y puede ejecutarse

-s "$FILE"

$FILE existe y su tamaño es mayor de cero bytes

Cualquiera de las condiciones anteriores puede ser precedida por el operador negación !, en cuyo caso la condición será cierta si no se satisface la comparación indicada. Por ejemplo, ! -d $DIR se cumplirá si $DIR NO es un directorio.

Asimismo, se permite crear condiciones múltiples mediante los operadores:

condicion1  -a condicion2

AND: Verdadero si ambas condiciones son verdaderas

condicion1  -o condicion2

OR: Verdadero si se cumple alguna de las dos condiciones

Recuerde las restricciones de sintaxis del shell en lo que respecta a los espacios, especialmente importantes en la escritura de las condiciones. Por ejemplo, la siguiente entrada dará error de sintaxis (el espacio tras ; sí puede omitirse):

# Falta espacio entre if y [
if[ condicion ]; then

Y la siguiente dará error porque buscaría el comando [comando] (incluyendo los corchetes como parte del nombre del comando), que en general no encontrará (mostrando un mensaje de orden no encontrada).:

if [comando]; then

TAREAS

  1. El comando test se puede ejecutar sin necesidad de utilizarlo en una estructura de control. Escriba la siguiente instruccion y analice su comportamiento (pruebe asignando también 1 a la variable V y una cadena de texto):

    V=0; [ $V -eq 0 ] &&
      { echo ES; echo 0; } ||
      echo ES 1
    
  2. El siguiente comando imprime por pantalla si el usuario actual es root. Ejecútelo como root y como un usuario normal:

    if [ "`id -u`" -eq 0 ]; then
      echo ROOT;
    fi
    
  3. Mire el contenido del siguiente script en su sistema y compruebe que tiene el permiso de ejecución:

    script_if.sh
    #!/bin/sh
    
    FILE=/tmp/archivo
    if [ -r $FILE -a ! -w $FILE ];
    then
       echo $FILE existe no modificable
    else
       echo No encontrado o modificable
    fi
    
    VAR1=1; VAR2=1
    if [ $(($VAR1)) -ne $(($VAR2)) ];
    then
       echo Distintos
    elif ls /; then
       :
    fi
    
  4. Ejecute los comandos siguientes y analice el resultado:

    rm –f /tmp/archivo
    ./script_if.sh
    
  5. Ejecute ahora los comandos siguientes y vuelva a analizar el resultado:

    touch /tmp/archivo
    chmod –w /tmp/archivo
    ./script_if.sh
    

3.5.6.3. Condicional: case

Presenta la siguiente sintaxis:

case cadena_texto in
  patron1) lista-compuesta1;;
  patron2) lista-compuesta2;;
  ...
  * ) lista-defecto [;;]
esac

cadena_texto debe aparecer obligatoriamente en la misma línea que la palabra reservada case (la palabra reservada in puede estar en la siguiente línea). En esta estructura, primero se expande cadena_texto (si es necesario) y busca el primer patrón que encaje con dicho valor. Cuando lo encuentre, ejecuta la lista compuesta correspondiente y finaliza la estructura. Los patronN se interpretan como cadenas de caracteres y si es necesario se expanden (por ejemplo, pueden contener variables). Admite los mismos caracteres que los usados para la expansión de ruta (*, ? y []). El patron * coincide con todo. Asimismo, pueden usarse patrones múltiples mediante el operador | y opcionalmente pueden comenzar con el paréntesis:

patronA  | patronB)

(patronA | patronB)

(patronC)

El doble punto y coma ;; permite determinar el final de los elementos a interpretar cuando se cumpla su patrón asociado. Por ese motivo, el ;; del último patrón puede omitirse. Es posible añadir espacios entre los patrones y los paréntesis abiertos ) que marcan el final del patrón. Conforme a esto, serían sintaxis válidas alternativas las siguientes:

# Alternativa 1
case cad_texto in
  patr)
    cmd1;
    cmd2;;
esac

# Alternativa 2
case cad_texto in
  patr )
    cmd1
    cmd2
esac

# Alternativa 3
case cad_texto in patr) cmd1; cmd2;; esac

# Alternativa 4
case cad_texto in (patr) cmd1; cmd2; esac

TAREAS

  1. Mire el contenido del siguiente script en su sistema y compruebe que tiene el permiso de ejecución:

    script_case.sh
    #!/bin/sh
    
    case $1 in
        archivo | file)
            echo Archivo ;;
        *.c)
            echo Fichero C ;;
        *)
            echo Error
            echo Pruebe otro ;;
    esac
    
  2. Ejecute los comandos siguientes y analice el resultado:

    ./script_case.sh archivo
    
    ./script_case.sh file
    
    ./script_case.sh file.c
    
    ./script_case.sh file.c++
    

3.5.6.4. Bucles incondicionales: for

Presenta la siguiente sintaxis:

for V in valores; do
  lista-compuesta
done

El nombre de la variable V debe aparecer obligatoriamente junto con la palabra reservada for en la misma línea. valores debe estar obligatoriamente en la misma línea que la palabra reservada in. El punto y coma ; puede sustituirse por un salto de línea, y viceversa. Así, por ejemplo, serían sintaxis válidas las siguientes alternativas:

# Alternativa 2
for V in valores; do lista-compuesta done

# Alternativa 3
for V
in valores
do
  lista-compuesta
done

# Alternativa 4
for V in valores
do
  lista-compuesta
done

valores se corresponde con un conjunto de valores (tomándose cada valor como una cadena de caracteres que puede ser objeto de expansión y como caracteres de separación los caracteres definidos en la variable IFS). La estructura for define la variable V (si no ha sido previamente definida). Para cada uno de los valores del resultado de expandir valores, la estructura inicializa la variable V con dicho valor y realiza una iteración (ejecutando lista-compuesta, en la cual suele ser habitual acceder al valor de la variable V).

Es posible omitir in valores. Si se omite equivale a haber escrito: in "$@"

TAREAS

  1. Ejecute el siguiente comando y compruebe como se puede utilizar una expansión de ruta dentro de un bucle for:

    for i in ~/.*; do
      echo Fichero oculto: $i;
    done
    
  2. Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución, invóquelo y compruebe el contenido del fichero ficherosalida que crea:

    script_for1.sh
    #!/bin/sh
    
    for i in 1 2 3; do
      echo "Iteracion: $i"
    done > ficherosalida
    
  3. Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución e invóquelo.

    script_for2.sh
    #!/bin/sh
    
    for file in `ls /`; do
      echo "Fichero: $file"
    done
    

Suele ser habitual el uso del comando externo seq para generar una lista de valores. Si bien este comando no está recogido en el estándar POSIX, es habitual su presencia en la mayoría de los sistemas UNIX. El comando seq presenta la sintaxis:

seq  valor_inicial  valor_final

siendo ambos valores números enteros. La salida del comando es la secuencia de números enteros entre ambos valores extremos indicados.

TAREAS

  1. Ejecute el comando siguiente y observe su salida:

    seq 1 10
    
  2. Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución general e invóquelo:

    script_for_seq.sh
    #!/bin/sh
    
    for i in `seq 1 3`; do
      echo "Iteracion: $i"
    done
    

    Compruebe cómo se obtiene el mismo resultado que al invocar el fichero script_for1.sh aunque mostrando el resultado a la salida estándar.

3.5.6.5. Bucles condicionales: while y until

Presentan la siguiente sintaxis:

# Bucle while
while lista-comp-condicion do
   lista-compuesta done

# Bucle until
until lista-comp-condicion do
   lista-compuesta
done

La lista-comp-condicion es una lista compuesta que se rige por las mismas directrices indicadas en la estructura if. La estructura:

  • while va iterando (interpreta lista-compuesta) mientras se cumpla la condición indicada (lista-comp-condicion devuelve el valor 0)

  • until va iterando (interpreta lista-compuesta) mientras NO se cumpla la condición indicada (lista-comp-condicion devuelve un valor distinto de 0).

Así, por ejemplo, serían válidas y equivalentes las sintaxis siguientes, si la condición del until es la condición del while negada:

# Alternativa 1
while l-comp-condW do
    cmd1
    cmd2
done

# Alternativa 2
until l-comp-condU do
    cmd1
    cmd2
done

# Alternativa 3
while l-comp-condW ; do cmd1; cmd2; done

# Alternativa 4
while l-comp-condW ; do { cmd1;cmd2;} done

TAREAS

  1. Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución e invóquelo:

    script_while.sh
    #!/bin/sh
    
    CONTADOR=0
    while [ $CONTADOR – lt 3 ]; do
      echo El contador es $CONTADOR
      CONTADOR=$(( $CONTADOR+1 ))
    done
    
  2. Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución e invóquelo:

    script_until.sh
    #!/bin/sh
    
    CONTADOR=0
    until [ $CONTADOR – ge 3 ]; do
      echo El contador es $CONTADOR
      CONTADOR=$(( $CONTADOR+1 ))
    done
    

    Podrá comprobar cómo ambos scripts devuelven la misma salida.

3.5.6.6. Ruptura de sentencias de control

Igual que en otros lenguajes de programación, como en el lenguaje C, es posible romper el funcionamiento normal de las estructuras repetitivas ( for, while y until). Sin embargo, hacerlo supone hacer código no estructurado. Por coherencia con lo visto en otras asignaturas, no se aconseja su uso.

En shell script esto se realiza con dos comandos internos: continue y break. Ambos son comandos internos de la shell con la siguiente sintaxis y funcionalidad:

  1. continue: utilizado en estructuras de control repetitivas para detener la iteración actual y continuar con la siguiente. Su sintaxis es:

    continue  [ n ]
    

    El parámetro opcional n es un número entero positivo que permite especificar la estructura de control en la que se desea detener la iteración. Si se tienen varias estructuras de control anidadas, la estructura actual en la que se encuentra el continue corresponde a la estructura 1; la estructura superior que engloba a ésta sería la estructura 2, y así sucesivamente. Así, el valor de n referencia a la estructura de control en la que deseamos detener la iteración actual y continuar con la siguiente (por omisión, n vale 1).

  2. break: utilizado en estructuras de control repetitivas para detener todas las iteraciones restantes de la estructura de control actual. Su sintaxis es:

    break  [ n ]
    

    El parámetro opcional n es un número entero positivo que permite indicar si se desean cancelar varias estructuras de control anidadas (por omisión, vale 1, que referencia a la estructura actual en la que se encuentra el break).

3.5.7. Funciones

Presentan la siguiente sintaxis:

Definición
fnombre() comando-compuesto [redir]
Invocación
fnombre  [arg1  arg2 … ]

El paréntesis siempre debe estar vacío (sólo indica que se está definiendo una función). Pueden insertarse espacios antes, entre y después del paréntesis. El comando compuesto puede ser cualquier de los que se han visto (agrupación de comandos, estructuras condicionales, estructuras repetitivas). Opcionalmente pueden aplicarse redirecciones a la función (afecta a los comandos que contiene, salvo que contengan una redirección explícita). A continuación se muestran ejemplos básicos de definición de funciones:

# Alternativa 1
fnombre(){
  comando1
  comando2
}

# Alternativa 2
fnombre() {
  comando1;
  comando2;
}

# Alternativa 3
fnombre() { comando1; comando2; }

En lo que se refiere al nombrado de las funciones, se aplican los mismos criterios antes expuestos para el nombrado de las variables.

El estándar permite que dentro de una función se invoque a otra. Los argumentos pasados a la función en su invocación son accesibles desde el cuerpo de la función mediante los parámetros posicionales $1, $2,…, $9, ${10},… Por tanto, dentro de la función, los parámetros posicionales no corresponden a los argumentos usados en la invocación del script.

Al igual que las variables, las funciones son:

  • Locales: sólo existen en el proceso shell en que son definidas.

  • Sólo son accesibles desde el momento de su definición hacia abajo del script, esto es, siempre deben definirse primero e invocarse después (no puede invocarse a una función que es definida más adelante).

  • Dentro de la función son visibles todas las variables y funciones definidas antes de su invocación. Y las variables definidas dentro de la función son visibles fuera tras la invocación de la función.

Dentro del cuerpo de la función suele ser habitual el uso del comando return, el cual provoca la salida inmediata de la función con el valor de retorno (número) indicado:

return  [ n ]

Si no se indica ningún valor de retorno, la función devuelve el valor del último comando ejecutado. Como siempre, el valor devuelto por la función puede obtenerse con la variable $?. return también puede utilizarse para terminar un script invocado implícitamente con ..

TAREAS

Mire el contenido del siguiente script en su sistema, compruebe que tiene el permiso de ejecución, invóquelo con 2 números enteros como argumentos y analice su funcionamiento:

script_funcion.sh
#!/bin/sh

suma () {
    C=$(($1+$2))
    echo "Suma: $C"
    return $C
    echo "No llega"
}

suma 1 2
suma $1 $2 #suma los 2 argumentos
echo "Valor devuelto: " $?