===== Programación en el shell =====
Este capítulo está excelentemente explicado en los
apuntes de Patricio Poblete en la sección
[[http://users.dcc.uchile.cl/~lmateu/CC3301/apuntes/Shell|shell]].
A esta sección solo hay que agregar que el shell permite definir
funciones, que en la práctica se comportan como nuevos comandos.
Estos comandos son más eficientes que un nuevo archivo de comandos
porque cuando se lanzan no crean un nuevo proceso, si no que
son interpretados por el mismo shell en donde se lanzan.
Por ejemplo se puede definir una función que calcula el factorial
de un número:
factorial()
{
if [ "$1" -gt "1" ]; then
i=`expr $1 - 1`
j=`factorial $i`
k=`expr $1 \* $j`
echo $k
else
echo 1
fi
}
while true
do
echo "Enter a number:"
read x
factorial $x
done
En las primeras versiones del shell de Unix no había ningún mecanismo predefinido para realizar cálculos aritméticos. Por eso se inventó el comando //expr// que realizaba la aritmética ausente en el shell. El comando expr no es parte del shell si no que es un comando con el mismo status que ls, cp, ps, etc. De la misma forma, el shell tampoco podía hacer comparaciones aritméticas En realidad la forma sintáctica //if// recibe un único comando como parámetro, lo ejecuta y luego determina si ejecuta la parte //then// o la parte //else// examinando el código de retorno de ese comando. Si es 0, se va por el then, si no el else. Es por eso que se inventó el comando ''['' para comparar expresiones. Se eligió ese nombre para que parezca una parentización.
Hoy en día, sí se han agregado esas características al shell porque lanzar comandos significa crear nuevos procesos y por lo tanto evaluar una expresión aritmética o comparar expresiones resultaba ineficiente. Por esta razón hoy en día el shell reconoce el ''['' como una sintaxis especial, y no crea un proceso. También se agregó la notación $(''(...)'') para evaluar expresiones aritméticas. La función factorial de más arriba se escribe más eficientemente de esta forma:
factorial()
{
if [ "$1" -ge "1" ]
then
f=`factorial $(($1 - 1))`
echo $(($1 * $f))
else
echo 1
fi
}