Taller Shell
Taller Shell
1. Recibir un nombre de archivo como parámetro e indicar imprimir todas las ayudas
que corresponda si el archivo es de lectura, escritura y ejecución por el usuario.
#upunto1.sh
#
clear
if [ -f ${1} ] || [ -d ${1}];
then
#valida si existe archivo o directorio
else
fi
echo
#Fin punto1.sh
clear
echo cantidad de parametros ingresados $·
#muestra el numero de parametros
echo Archivos Encontrados:: $* #
#cada uno de los parame. en orden de ingreso
echo
for i in $*
do
if [ -f ${i} ] && [ -d ${i} ] ;
then
#si son ambos
echo `ls -lt ${i}`
echo "El nombre corresponde para ambos (archivo comun y directorio)"
elif [ -f ${i} ];
then
#si es un archivo comun
echo `ls -lt ${i}`
echo "El nombre corresponde a un archivo comun"
elif [ -d ${i} ]; then
#si es un directorio
echo `ls -d -lt ${i}`
echo "El nombre corresponde a un directorio"
else
echo "No existe ni archivo ni directorio con ese nombre o similar"
fi
echo
done
#Fin punto2.sh
Deberemos saber también que con la ayuda solamente de la conjunción de comandos no podremos hacer script verdaderamente
interesantes. Por esto se incorporan las construcciones de shell. Estas son las construcciones while, for-in, if-then-fi y case-
esac. Existen muchas más pero estas serán las más útiles para nosotros en estos momentos. Para mayor información sobre otro tipo de
construcciones seria mejor revisar las páginas de manual del intérprete de comandos bash (man bash).
Empezaremos viendo un uso sencillo de la construcción for-in que tiene la siguiente sintaxis
Aquí tenemos varias cosas para ver. Primero que nada, el uso de las variables posicionales. Como se podrá apreciar el número de la
variable, que esta precedido por un signo $, indica la posición del argumento cuando el script es llamado. Solamente se podrán usar 9
variables de este tipo sin tener que emplear un pequeño truco de corrimiento que veremos luego, dado que el 0 representa al nombre del
script mismo. Es decir que en este caso la variable posicional $0 valdrá "miscript". Como se puede ver se han utilizado canalizaciones
para poner más de un comando junto. Al final de la construcción se esta usando una construcción while. Esta se usa para repetir un
ciclo mientras una expresión sea cierta.
while ($VARIABLE=valor)
do
commandos
done
En este caso esta siendo usada al final de una canalización con la instrucción read ARCHIVO. Es decir, mientras pueda leer el
contenido de la variable $ARCHIVO, continuar. Esta variable $ARCHIVO contiene el resultado de lo que arrojo la canalización del listado
con la salvedad de que tenia que contener la palabra que le enviamos como argumento, es así que solo se imprimirán las líneas en las
que coincida la palabra a buscar de los archivos que cumplan con los requisitos.
Otra cosa a tener en cuenta es una nueva construcción en este script, ${1}/${ARCHIVO}. Al encerrar un nombre de variable dentro de
llaves podemos combinarlas. En este caso forman el nombre del directorio ( ${1}) y añadimos una / como separador del directorio, y
seguido e nombre del archivo donde se aplicara el comando grep con la palabra a buscar $3.
Podríamos hacer que este script sea un poco más documentado. Para esto podríamos asignar las variables posicionales a otras variables
para que se pueda entender mejor su uso.
DIRECTORIO=$1
ARCHIVO_BUS=$2
PALABRA=$3
DIRECTORIO=$1
shift
ARCHIVO_BUS=$1
De esta manera podríamos asignar el valor de la primer variable posicional a la variable DIRECTORIO y luego el siguiente argumento
que habíamos dado se tomara otra vez con el nombre de $1. Esto solo tiene sentido si asignamos las variables posicionales a otra
variable. Si tuviéramos 10 argumentos, el décimo no estaría disponible. Sin embargo, una vez que hacemos el que las variables se corran
de posición este se convertirá en el noveno y se accederá por la variable posicional $9. Existe una forma también de pasar como
argumento a la instrucción shift el número de posiciones que queremos correr. Por lo cual podemos usar
shift 9
y así se lograra que el décimo argumento sea el parámetro posicional 1.
Lo que ocurre con los anteriores 9 argumentos es que desaparecen si no se los asigno a una variable anteriormente. Podremos cambiar
usar un nuevo parámetro que podrá contener mas de un parámetro pasado al script. Este se denomina $* y contendrá el resto de los
argumentos que se pasen al script luego de que se haya realizado un corrimiento determinado. Por ejemplo, si quisiera buscar una frase
en lugar de una única palabra el script podría ser
DIRECTORIO=$1
ARCHIVO_BUS=$2
shift 2
PALABRAS=$*
Otro parámetro que es de utilidad es el $# que lleva la cuenta de la cantidad de argumentos pasados al script. De esta forma podríamos
realizar un script que identificara si se le están pasando la cantidad de parámetros que realmente necesita y anunciar el error si faltaran
estos. Para ello utilizaremos la construcción if-then-fi que es muy parecida a la while-do-done, en donde el par if-fi marca
el final de un bloque. La diferencia entre estas construcciones es que el if solo evaluara una vez la condición. La sintaxis es la siguiente
if [ condición ]
then
hacer_algo
fi
Las condiciones que puede usarse se encuentran en las man page test (man test). Nosotros usaremos una simple condición para contar
argumentos, pero pueden ser usadas distintas condiciones como nombres de archivos, permisos, si son o no directorios, etc. Para saber si
la cantidad de argumentos que se nos a pasado en el script es correcta, utilizaremos una opción aritmética que compare la cantidad de
argumentos pasados ($#) con un número que nosotros estipularemos, en este caso 3. Pueden usarse diferentes opciones con el formato
arg1 OP arg2, donde OP será alguno de los siguientes
-eq es igual
-ne no es igual
-lt menor que
-le menor que o igual
-gt mayor que
-ge mayor que o igual
Se usará en este caso el -ge (mayor o igual que) dado que si la cantidad de argumentos que siguen al segundo es mayor la tomaremos
como una frase a buscar y si es igual como una palabra. Lo único que haremos en caso de que la cantidad de argumentos sea menor,
será informar de esto y de la forma de usar el script.
DIRECTORIO=$1
ARCHIVO_BUS=$2
shift 2
PALABRAS=$*
if [ $# -ge 3 ]
then
ls $DIRECTORIO | grep $ARCHIVO_BUS | while read ARCHIVO
do
grep "$PALABRAS" ${DIRECTRIO}/${ARCHIVO}
done
else
echo "Número de argumentos insuficientes"
echo "Use: $0 <directorio> <archivo_a_buscar> <palabras>"
fi
Otra utilidad para del if, es la posibilidad de realizar lo que se denomina if anidados. De esta forma podríamos tener varias capas de if-
then-else-fi. Como ejemplo podría ser esta una construcción válida
if [ $condicion1 = "true" ]
then
if [ $condicion2 = "true" ]
then
if [ $condicion3 = "true" ]
then
echo "las condiciones 1, 2 y 3 son ciertas"
else
echo "solo son ciertas las condiciones 1 y 2"
fi
else
echo "condición 1 es cierta, pero no la 2"
fi
else
echo "la condición 1 no es cierta"
fi
Podríamos también hacer que una sola variable tome diferente valores e interactuar con ella para ver si se cumple la condición buscada.
De esta forma podríamos por ejemplo hacer un menú de usuario con distintas alternativas. Pero esta forma es útil solo para pocas
condiciones. ¿Que pasaría si tuviéramos muchas condiciones mas que agregar? Se nos haría por demás de complicado seguir el
esquema armado y sería demasiado código para lo que se trata de realizar. Es aquí es donde se necesita la estructura case-esac.
Como se podrá ver, al igual que en el if-fi aquí el inverso de case (esac) cierra la construcción. Veamos un ejemplo de una
construcción con case
read ELECCION
case $ELECCION in
a) programa1;;
b) programa2;;
c) programa3;;
*) echo "No eligió ninguna opción valida";;
esac
Hay que tener en cuenta algunas cosas respecto a este tipo de construcción. Por ejemplo el mandato que le damos al principio read indica
al bash que tiene que leer lo que se ingrese a continuación y lo guarde en una variable que se llamara ELECCION. Esto también será útil
para el uso de otras construcciones ya que el read no es propiedad exclusiva de la construcción esac, sino que pertenece al mismo
bash. Como se ve, se le indica que si el valor que la variable contiene es igual a alguna de las mostradas debajo se ejecute determinado
programa. (case $ELECCION in). La elección se debe terminar con un paréntesis ")" para que se cierre las posibilidades. Podríamos
poner más posibilidades para cada elección; lo único que hay que recordar es cerrar con un paréntesis. El punto y coma nos marca el final
de un bloque, por lo que podríamos agregar otro comando y se cerrara con punto y coma doble al último. El asterisco del final nos indica
que se hará en caso de que no coincida lo ingresado con ninguna de las posibilidades. Un ejemplo, sería que nuestra construcción
reconozca mayúsculas y minúsculas y además ejecute más de un comando por bloque.
read ELECCION
case $ELECCION in
a|A)
programa1
programa2
programa3;;
b|B)
programa4
programa5;;
c|C)
programa3;;
*)
echo "No eligió ninguna opción valida";;
esac
También se podría haber incluído un rango de posibilidades
[shrek@pantano:~]$ . miscript
Un script puede dejar cosas sueltas antes de terminar si éste es finalizado bruscamente enviándole una señal de finalización [1] ya sea
con la combinación de teclas Ctrl-C o con un kill -15. Para esto se deberán capturar estas señales para poder hacer una limpieza, ya
se de variables o archivos, antes de finalizar. La forma de hacerlo es con el uso del comando trap; de esta forma se capturará la señal que
se le envíe al script y se podrá ya sea ignorar la misma o ejecutar otro comando de limpieza. Para demostrar esto haremos un pequeño
script que servirá de menú. La llamada al script del menú podría estar en el archivo .profile del usuario o en el .bash_profile. Si
lo que no queremos es que el usuario salga del script con usando la combinación de teclas Ctrl-C, lo que haremos es capturar la señal y
hacer que se ejecute nuevamente el script que se llamará simplemente menu.
trap './menu' 2
while :
do
echo 'a) Listado de archivos'
echo 'b) Día y hora actual'
echo 'c) Mes actual'
echo 'Seleccione: '
read ELECCION
case $ELECCION in
a|A) ls;;
b|B) date;;
c|C) cal;;
*) echo "No eligió ninguna opción valida";;
esac
done
Como se ve al principio del script se utiliza el comando trap que al captura la señal 2 (SIGINT) que produce el Ctrl-C relanza el script. Al
final del script se ve que se llama nuevamente dado que al ejecutarse el comando de cada elección se quiere que el menú siga
funcionando. Practicar con estas construcciones será de gran ayuda para entender el proceso de construcción de script y los preparara
para script más complejos usando otros interpretes como el sed, awk y el lenguaje perl. Para mayor información respecto a la
construcción de script, remitirse a las páginas de manual del intérprete de comandos, en este caso man bash.