El shell es tanto un interprete de comandos como un lenguaje de programacion; para sacarle el maximo provecho conviene aprenderse algo de ese lenguaje. El proposito de esta leccion es de facilitar este aprendizaje.
Como hemos dicho, hay dos versiones de shell: el original sh
de ATT, y todos sus sucesores (bash, ksh);
segundo el csh y sus derivados (tcsh). En esta
leccion concentraremos en el sh, dejando csh marginado.
Las cosas a aprenderse pueden resumirse en la siguiente lista; recomendamos que la primera vez que la use lo haga en el orden dado; despues puede hacerlo en orden arbitrario.
var=valor
Aqui var puede ser cualquier combinacion de letras que
empieze por lafabeticas, distinguiendo minusculas y mayusculas. Por
ejemplo
Xabc=23
nombrelargo=abc
Para usar una variable, se coloca su nombre precedido del signo
"$". Esto causa que el valor (mano derecha) de la variable se
sustituya donde aparece el "$". Por ejemplo:
abulafia%Aqui vemos como el shell sustituye el valor de la variable (Xabc) por su valor (23). Si una variable es indefinida, (no ha sido usada a mano izquierda de una asignatura) tiene valor nulo, es decir, no se sustituye nada. No se considera un error usar una variable nula.Xabc=23abulafia%echo valor $Xabcvalor 23
x1=23
x2=ab
echo $x1$x2
Como haria para que una variable x3 valiera la encadenacion de otras dos
(en este caso, para que x3 == 23ab .
En csh, la sintaxis para asignar es
abulafia%y el uso es exactamente igual aset Xabc 23
sh.
Ir a: Principio, Seccion.
Primero veamos como hacer que una variable se incorpore a la guarderia; en
Ir a: Principio, Seccion.
El siguiente ejemplo cuenta los archivos en un directorio (
El if-then-else se usa para estos casos. La sintaxis es
Ir al principio
La sintaxis es
La
La lista se puede especificar de varias maneras:
Por ejemplo,
Ir al principio
La sintaxis del comando es:
Ir al principio
El shell script se crea con cualquier editor y se le cambia luego el modo
a "ejecutable" para indicarle al shell que es un guion. (Ver el comando
Un shell script puede tener argumentos como cualquier comando de Unix.
Los argumentos se colocan en variables posicionales, llamadas
La ventaja de una funcion de shell es que ahorra un archivo y algun tiempo
de carga en comparacion con un shell script.
Ir al principio
Ir al principio
Ir al principio
Variables globales y locales
Tal como los lenguajes de programacion tienen variables globales
(por ejemplo, FORTRAN tiene variables que estan en COMMON), el shell tiene
dos tipos de variables: unas que sobreviven todas los forks y
execs del shell y otras que no. En efecto, el shell mantiene
una especie de ``guarderia'' para las variables globales, llamada el
environment o ambiente; el ambiente esta disponible a cualquier
programa invocado por el shell.
sh esto se hace asi:
abulafia%
En Xabc=23; export Xabc
ksh o bash:
abulafia%
Para ver lo que tenemos en la guarderia, un nuevo comando:
export Xabc=23
abulafia%
En mi maquina, esto produce:
env
Algunas lineas han sido recortadas (indicadas por ---). Como se puede ver,
hay bastantes cosas en la guarderia. Las mas importantes son:
ignoreeof=0
LOGNAME=juanr
MINICOM=-c on
MAIL=/var/spool/mail/juanr
TERMCAP=xterm|vs100|xterm terminal emulator (X window system):---
TERM=xterm
HOSTTYPE=i386
PATH=:/bin:/usr/bin:/usr/local/bin:/u/juanr/bin:/usr/TeX/bin:---
HOME=/home/juanr
SHELL=/bin/bash
PS1=\w>
PS2=...
MANPATH=/usr/man:/usr/man/preformat:/usr/X11/man:
LESS=-MM
DISPLAY=:0.0
GSVGAMODE=G320x200x256
WINDOWID=16777229
SHLVL=4
BASH=/bin/bash
_=/usr/bin/env
La variable HOME: nuestro directorio hogar o habitual.
PATH: los directorios donde el shell busca programas
para ejecutar. Los directorios se revisan en el orden dado; se separan con
el signo de los dos puntos (:).
TERM: el tipo de terminal. (Necesario para los
editores.)
SHELL: el nombre del shell (en este caso bash)
PWD contiene el nombre del directorio actual.
Sustitucion o no de variables
A veces es necesario suprimir la sustitucion de variables. Por ejemplo,
cuando queremos atribuirle al signo "$" su significado de todos los dias:
abulafia%
Este resultado se debe a que el shell busca la variable 25-- y no la
encuentra, por lo tanto es nula. Esto nos trae al uso de comillas,
las cuales se usan para controlar la sustitucion. Hay tres tipos de
comillas con diferente significado:
echo El precio es $25
El precio es
Comillas sencillas (')
Las comillas sencillas inhiben totalmente la sustitucion. Por lo tanto,
podemos reescribir el ejemplo anterior:
abulafia%
echo 'El precio es $25'
El precio es $25
Comillas dobles (")
Las comillas dobles inhiben sustitucion de todo menos $ y a veces
\. Por ejemplo, no se interpreta el asterisco. Esto dice que dentro de
comillas dobles se sustituyen variables pero mas nada. Probablemente esto
sea la mejor forma de producir mensajes, y uno debe acostumbrarse a
ponerle doble comillas a los mensajes:
abulafia%
echo "Ud esta en el directorio $PWD"
Ud esta en el directorio /u/juanr/Mosaic
Comillas graves (`)
Estas comillas, asi llamadas por parecerse al acento grave del
frances, se usan para asignar el resultado de un comando a una variable.
En efecto se ejecuta todo lo que esta entre las comillas graves, y el
resultado de los comandos, que normalmente va a la pantalla, se puede
usar como variable.
wc
es un comando que cuenta palabras o lineas o bytes de un archivo)).
abulafia%
Debo mencionar que por lo menos en ls | wc -w wc cuenta palabras
22
abulafia%arch=`ls | wc -w` asignamos por grave
abulafia%echo "Hay $arch en este directorio"
Hay 22 en este directorio
bash vale esto ``en un
solo saque'':
abulafia%
Es decir, valen comillas graves dentro de comillas dobles. Tambien es mas
dificil de leer.
echo "Hay `ls | wc -w` archivos"
Ejercicio
Que pasa con comillas graves dentro de comillas sencillas?
Que pasa con comillas dobles dentro de comillas graves?
Ejecucion condicional (if-then-else)
Hay veces que se quiere ejecutar uno o mas comandos solo bajo ciertas
condiciones. Las condiciones pueden ser, por ejemplo, la existencia (o no)
de un archivo, si tal variable es igual a tal valor, etc.
En este ejemplo, el punto suspensivo (...) representa cualquier cantidad
de comandos. El
if [ condicion ]
then
...
else
...
fi
else es opcional. Veamos ahora el problema
de especificar condiciones.
Condiciones
Las condiciones estan documentadas en el manual bajo el programa
test; de hecho el corchete izquierdo ([) es sencillamente un
link al programa test. Hay una gran cantidad de condiciones
que se pueden especificar (haga man test para verlas todas):
if [ -x arch ] : valido si arch existe
if [ -f arch ] : valido si arch existe y no es nulo
if [ s1 = s2 ] : si caracteres s1 son iguales a s2
if [ n1 -eq n2 ] : si enteros n1 y n2 son iguales
Advertencia
Hay que dejar espacio en blanco entre el if y su corchete;
entre los corchetes y su contenido y entre los argumentos del contenido de
los corchetes. No funcionan los siguientes ejemplos:
En general, el shell es exigente con los espacios en blanco.
if[ -x arch]
if [ n1=n2 ]
if [ n1 = n2]
Detalle
Se puede poner el then en la misma linea que el
if, separado por punto y coma:
if [ -f archivito ] ; then
....
fi
Ejecucion iterada (for-do-done
La ejecucion iterada o for nos permite ejecutar repetidamente una
serie de comandos, variando sistematicamente uno de los elementos de esa
ejecucion.
for i in lista-de-valores
do
....
done
i se llama la variable de lazo (loop variable).
EL punto suspensivo representa cualquier cantidad de comandos. Estos son
ejecutados sucesivamente avriando los valores de i, tomados
de la lista. Por supuesto la variable de lazo se puede llamar cualquier
cosa.
for k in 1 2 3 4 5 # especificacion directa de la lista
for k in *.f # como especificacion de archivos
for i in *.f code.c # combinacion
code>
for i in 1 2 3 4 5 ; do
echo "i vale $i"
done
Notese que hemos puesto el do en la misma linea que el
for, separados por punto y coma. Esto produce:
i vale 1
i vale 2
i vale 3
i vale 4
i vale 5
Notese que se puede redireccionar la salida del for completo:
Lo cual redirecciona todo a
for i in 1 3 7 ; do
...
done >archivo
archivo.
Ejecucion repetida condicionalmente (while)
El equivalente del conocido do while de varios lenguajes. Permite
repetir comandos mientras valga una condicion.
Las condiciones son iguales que para el
while [ condicion ]
do
....
done
if (es decir, como en
el caso de if, el corchete es el comando test.)
Por ejemplo:
Esto produce sucesivamente 4, 8, 16, 32, 64, 128, 256.
p=2
while [ p -lt 256 ] ; do
p=`expr $p + $p`
echo $p
done
Shell Scripts y Argumentos Posicionales
La anteriores figuras pueden ser emitidas "sobre la marcha", sencillamente
tipeando comandos como lo hemos indicado. Por ejemplo:
abulafia%
Notese en este punto que el prompt de abulafia es reemplazado por
el signo >. Esto se llama el prompt secundario y quiere decir
que hay una figura incompleta (es decir, falta algo). Para completar,
hariamos por ejemplo
for i in * ; do
>
> echo $i # todavia incompleto
> done # listo
(...) # aqui va la salida
abulafia%
Los dos prompts se controlan con las variables de shell PS1 y PS2.
Por ejemplo, emitiendo
El porcentaje en el concido prompt de abulafia se transformaria en la
"zanahoria" (PS1) y el prompt segundario seria el punto suspensivo.
PS1="abulafia>"
PS2="..."
Shell Scripts
Sin embargo, es a veces engorroso ingresar largas series de comandos. En
este caso, las podemos ingresar a un archivo, y luego pedirle al shell que
ejecute cada linea de ese archivo como si lo hubieramnos hecho desde el
teclado. Estos archivos se llaman shell scripts o "guiones de
shell", como guiones de teatro. (En este caso el "actor" que interpreta el
"guion" es el shell".
chmod para cambiar el modo.
$1, $2... $1.
Por ejemplo, si miscript es un shell script que tiene este
aspecto:
y ahora lo invocamos asi:
echo "mis tres primeros argumentos son $1 $2 $3"
abulafia%
Pueden usarse cualquier cantidad de argumentos, en grupos de 10. Es decir,
inicialmente solo hay 10 argumentos. El comando miscript alfa beta gamma
mis tres primeros argumentos son alfa beta gamma
shift causa
que el onceavo argumento pase al primero, el doceavo al segundo.. etc.
El argumento $0 siempre es el nombre del shell script. La variable
$# nos da el numero de argumentos. Por ejemplo, creemos un
shell script llamado scr2 que contiene estos comandos:
echo "Este es el script $0"
echo "Argumentos $1 $2 $3 $4 $5 $6 $7 $8 $9 $10"
if [ $# -gt 10 ] ; then
shift # $1 <- $11 etc
echo "El onceavo argumento es $11"
fi
Si invocamos a este script con mas de 10 argumentos por ejemplo:
abulafia% scr2 1 2 3 4 5 6 7 8 9 10 11 12
Este es el script scr2
Argumentos 1 2 3 4 5 6 7 8 9 10
El onceavo argumentos es 11
Funciones de shell
Las funciones de shell se parecen a los shell scripts, pero no
residen en un archivo. Se definen una vez (por sesion login) y el shell se
recuerda de ellos. La sintaxis es:
La definicion puede ser cualquier cantidad de comandos. Por ejemplo
nombre() { definicion; }
nos permite ver "tar comprimido" (lo cual veremos mas adelante **)
(El uso seria por ejemplo "ver aaa.tar.Z").
ver-tar(){ zcat $1 | tar tvf -; }
La historia de comandos
El shell (ksh) guarda una historia de los N ultimos comandos ingresados
por la consola. Estos se pueden recuperar, cambiar, y volver a ingresar.
(Generalmente N = 128). Se reconocen dos opciones pertinentes:
Estas dos opciones son mutuamente exclusivas. Para cambiar los comandos,
se puede emular a vi o emular a emacs. Vease "man shell".
set -o emacs
set -o vi
Control de trabajo
Esto se refiere a poder correr multiples tareas concurrentemente. El
ksh permite correr procesos en dos estados: foreground
o interactivo y background o "en el fondo". (En realidad, lo que
quiere decir esto es que el proceso no espera al terminal.) Cuando se
inicia un trabajo con un comando, es interactivo. Un trabajo interactivo
se puede pasr al fondo con la siguiente secuencia:
abulafia%
Es decir, ingresamos control-z (oprimir control sin soltarla oprime
z; esto suspende al proceso programa-largo. Ahora, para que pueda seguir
ejecutando,
programa-largo # arranque
^Z # control-z
[1] + Stopped
abulafia%
Esto manda el ultimo proceso suspendido al fondo, asignandole el numero de
trabajo 1. Para ver que cosas tenemos corrriendo, usamos
bg
[1] programa-largo &
abulafia%
Por ultimo, podemos eliminar a cualquier "job" por medio del comando de
shell jobs
[1] Running programa-largo &
kill (no es el mismo comando usado para matar procesos)
en cuyo caso usamos el porcentaje para identificarlo:
abulafia%
Si kill %1
[1] Killed programa-largo &
programa-largo termina por propia cuenta, el shell nos
dara un mensaje con el identificador del job, que dice "Done".
Ultima revisión: marzo 1998.
Autoría: Dr. Juan Rivero,
Instituto Venezolano de Investigaciones Científicas (IVIC).
Se permite copia local, siempre y cuando se conserve esta autoría.