Como se vió al principio del curso, la shell nos permite acceder al kernel del sistema operativo. La shell en reaildad lo que hace es interpretar la línea de comandos y ejecutar los programas que ésta indica. Sin embargo, además de leer la línea de comandos, también puede ejecutar los comandos que se encuentren en un fichero. Cualquier comando que pueda ser tecleado en la línea de comandos puede ser incluido en un fichero al que se le denomina como shell script o shell program.
Un shell script es un fichero donde hemos introducido cualquier comando que se puede ejecutar en la shell. Se pueden incluir comandos UNIX, utilidades, emplear pipes, redireccionar entradas y salidas, definir y utilizar variables, además del uso de una serie de comandos UNIX creados para ser usados fundamentalmente en los shell scripts, como son condicionales y comandos para controlar el flujo del programa.
Estos comandos UNIX especificos de los shell scripts, suelen tener una sintaxis distinta dependiendo de la shell empleada. Hay dos opciones básicas que tienen a su vez algunas diferencias. Por un lado están la Korn shell y la Bourne Again shell, que tienen un lenguaje similar al de la shell original de UNIX (Bourne shell). Por otro lado están la C shell y la TC shell que son muy similares entre si (en el curso utilizaré esta opción aunque cada vez es más frecuente utilizar la Korn shell).
Vamos a empezar con un ejemplo muy sencillo. Creamos un fichero que se llame INFO y escribimos en el los siguientes comandos:
# Script que nos muestra por pantalla la fecha, la hora, la maquina en que # estamos, nuestro username, nuestro numero identificador de usuario y de # grupo, quien esta conectado a la maquina y el directorio en que estamos echo "la fecha de hoy es `date`" echo "La maquina en que estas trabajando es: $HOST" echo "" echo -n "Tu user name es: " whoami echo "Los numeros identificadores de usuario y de grupo son:" id echo "" echo "En la maquina estan conectadas las siguientes personas " who echo "Estas en el directorio `pwd`"
Luego ponemos el fichero en un directorio al que haga referencia la variable
PATH. Normalmente los usuarios tienen definido el directorio
bin, donde ponen sus ejecutables y al
que hace referncia la variable PATH. Finalmente le damos permiso
de ejecuión al fichero.
chmod a+x INFO
Ahora podemos teclear en la línea de comandos desde cualquier directorio
INFO
y se ejecutarán los comandos incluidos en el fichero.
Este es un sencillo ejemplo de shell script en que simplemente se ejecutan una serie de comandos secuencialmente. Sin embargo las posibilidades que permite la programación en shell son mucho más amplias.
El script INFO sólo usa comandos estandard
de UNIX que funcionan en cualquier
shell. Si vamos a crear un shell script que usa características
especificas de una shell en concreto, tenemos que indicar al principio del
script en que shell queremos que se ejecute. Para ello se pone
en la primera línea del script los caracteres #!
seguido de la ruta de acceso al fichero ejecutable que corresponde a la shell.
Por ejemplo para especificar que el script se ejecute en una C shell pondremos
en la primera línea:
#!/bin/csh
donde /bin/csh es la ruta de acceso al programa que ejecuta
una nueva C shell. De esta forma el fichero ejecuta
una C shell y los comandos que van acontinuación se ejecutan como
subprocesos de esta C shell.
Los scripts pueden ejecutarse con argumentos introducidos desde la línea de comandos. Para utilizar un determinado argumento en el shell script nos referimos a el con $ seguido de un número que indica la posición en la línea de comandos en que fué introducido. Veamos el siguiente ejemplo:
#!/bin/csh #Ejemplo para ver como se pasan argumentos a un shell script #Imprime los argumentos en orden inverso (hasta un maximo de 9) echo "los argumentos introducidos son : $9 $8 $7 $6 $5 $4 $3 $2 $1"
Dentro de los shell scripts podemos usar el comando set para
definir las variables de la misma forma que se hace en la línea
de comandos. Veamoslo ahora con más detalle.
set varname=value
set varname[n]=word
value puede ser una palabra (o una cadena cualquiera de
caracteres entre comillas), o puede ser una serie de palabras separadas
por espacios, en cuyo caso hay que ponerlas entre parentesis). De esta
forma se definen variables con indice. Para asignar un valor a
un sólo indice se utiliza el segundo formato.
Para aclarar todo esto veamoslo con el siguiente ejemplo en el que creo el script ejemp2 que simplemente muestra una serie de variables.
#!/bin/csh #Ejemplo para ver como se definen las variables y #mostrar algunas variables especiales set text1="Esta variable tiene solo un indice" echo "El numero de indices de la variable text1 es $#text1 y su valor es:" echo $text1 echo "" set text2=(Esta variable tiene varios indices) echo "El numero de indices de la variable text2 es $#text2 y sus valores son:" echo $text2[*] echo "" echo "Has tecleado $#argv argumentos que son: $argv" echo "" echo "El valor de la variable path es:" echo $path echo "" echo "La shell en que se ejecutan los comandos del script es $shell" echo "El PID de este script es $$ y el nombre del comando $0" echo "" echo "Teclea una linea en la terminal" echo "Has tecleado: $<"El resultado de ejecutar este ejemplo introduciendo como argumentos:
El numero de indices de la variable text1 es 1 y su valor es: Esta variable tiene solo un indice El numero de indices de la variable text2 es 5 y sus valores son: Esta variable tiene varios indices Has tecleado 4 argumentos que son: a b c d El valor de la variable path es: /home/fcabrera/bin /usr/bin /usr/sbin /usr/ccs/bin /usr/dt/bin /usr/openwin/bin /opt/local/bin /opt/SUNWspro/bin /usr/ucb /usr/local/bin /usr/X11/bin /opt/hpnp/bin . /usr/SUNWwabi/bin /opt/gnu/bin /usr/gipsy/exe/sol4 /net/lisa/lisa3/fcabrera/l3/c84/ /net/lisa/lisa3/fcabrera/c90 La shell en que se ejecutan los comandos del script es /bin/csh El PID de este script es 29897 y el nombre del comando ejemp2 Teclea una linea en la terminal Esto es solo un ejemplo Has tecleado: Esto es solo un ejemplo
La shell nos permite definir variables con valores númericos y realizar
determinadas operaciones aritméticas que puden ser muy útiles
en los shell scripts. La sintaxis para definirlas es:
@ variable = valor
Los operadores que podemos usar son:
+ Suma - Resta * Multiplica / Divide (parte entera) % Resto de una divisiónPor ejemplo el comando:
Puede utilizarse el comando if para ejecutar comandos según se cumpla o no una condición. La estructura de un comando if es:
if (expr) then ... else if (expr2) then ... else ... endif
Veamos un ejemplo sencillo:
#Ejemplo para mostrar el funcionamiento de if
#Comprueba si existe un fichero en el directorio, si esta nos ejecuta ls -l
#Si no esta nos dice "no existe un fichero con el nomgre ..."
ls $1>/dev/null
if ($status != 0) then
echo "No existe el fichero $1"
else
ls -l $1
endif
Primero se hace un ls del fichero buscado, enviando la salida al dispositivo /dev/null porque no nos interesa. Luego comprueba si el valor de la variable status es distinto de 0. Esta variable se define automáticamente y su valor depende de si el comando anterior (ls) tiene exito, en cuyo caso tendrá un valor de 0, o da algún error, en cuyo caso su valor será distinto de 0. Así pues, si el fichero existe status valdra 0 y se ejecuta ls -l y si el fichero no existe, status tendrá otro valor y se ejecuta echo "No existe el fichero $1".
Los operadores lógicos y de comparación que se pueden usar en las
expresiones son:
OPERADORES LOGICOS ! NOT && AND || OR OPERADORES DE COMPARACION == Igual (enteros o cadenas de caracteres) != Distinto (enteros o cadenas) =~ La cadena de la izquierda se ajusta al patrón de la derecha !~ La cadena de la izquierda no se ajusta al patrón de la derecha > Mayor que (enteros) < Menor que (enteros) >= Mayor o igual (enteros) <= Menor o igual (enteros)Además se pueden usar los paréntesis.
Su estructura es la siguiente:
foreach var (wordlist)
...
end
La variable va tomando cada uno de los valores de la lista y para cada valor se ejecutan los comandos comprendidos entre foreach y end. Veamos un ejemplo:
#!/bin/csh
#Ejemplo para mostrar el funcionamiento de foreach
#Cambia de minuscula a mayuscula el contenido de los ficheros
#que se introducen como argumentos en la linea de comandos escribiendolos
# en un fichero con el mismo nombre y extension.M
foreach f ($argv[*])
set name=$f.M
cat $f | tr 'a-z' 'A-Z' > $name
end
La variable f va tomando cada vez el nombre de uno de los argumentos. Se define luego la variable name que será igual al nombre de entrada con la extensión .M. El comando cat envía el contenido de cada uno de los ficheros de entrada al comando tr (que es el que transforma las minúsculas en mayúsculas) y este envía la salida a el fichero con el mismo nombre y extensión .M.
Vamos a ver un ejemplo de un shell script algo más elaborado que combina foreach e if. El script se ejecuta como:
#!/bin/csh
#Script que mata todos los procesos que tengamos corriendo en una maquina
#La sintaxis es mata seguido del nombre de la maquina
if ($#argv != "1") then
echo "Introducir como argumento el nombre de la maquina"
exit
endif
set pid=`rsh $1 ps -feao ruser,pid | grep $user`
foreach pro ($pid)
if ($pro != $user) then
rsh $1 kill -9 $pro
endif
end
La sintaxis del comando es:
switch (string) case label1: ... case label2: . . ... breaksw ... default: ... breaksw endsw
Se va comparando si las etiquetas label1, label2 ... coinciden con la cadena string, en cuyo caso se ejecutan los comandos que van a continuación. en el momento que se encuentre un breaksw continuará con los comandos que siguen después de endsw. Si no se encuentra ningún breaksw se llega a default: y se ejecutan los comandos que siguen. Si tampoco hay default: el programa continua su ejecución después de endsw.
La sintaxis es:
while (expr) ... end
Su funcionamiento es muy simple. Mientras la evaluación de la expresión entre parentesis sea verdadera (distinto de 0) se ejecutarán los comandos comprendidos entre while y end.
Existen otros comandos que son muy útiles en la programación en shell, pero que su explicación queda fuera de los objetivos de este curso. Para los que quieran profundizar en el tema se muestran a continuación los más importantes con un ejemplo sencillo:
awk (pattern scanning and proccesing language)
Permite buscar
patrones de caracteres en ficheros y realizar una serie de acciones cuando
encuentra una coincidencia entre el patrón y una línea. Ejemplos:
awk '$4 ~/agn/ {print $1,$9}' log
Busca el patrón agn en la columna 4 de cualquier línea del fichero
log, y para las líneas en que encuentre el patrón realiza la
acción
indicada entre {}, que en este caso es mostrar la columna 1 y la 9.
sed
Permite modificar el contenido de un fichero (sustituir palabras,
añadir, borrar, etc) según indiquen una serie de comandos. Un ejemplo
sencillo es:
sed -e "s/[Gg]alaxia/NGC4151/g" file
Remplazará en cada línea del fichero file la palabra
galaxia o Galaxia
por NGC4151.
cut and paste
Cortan y pegan campos seleccionados de cada línea de un ficheros. Ejemplos:
cut -c 1-5 file1
paste l1 l2
El primero extrae por la terminal los cinco primeros caracteres de cada línea
del fichero file1. El segundo une la línea los dos ficheros
l1 y l2 mostrandolo
por la terminal.