Logo Studenta

Introducción al uso y administración del sistema operativo Linux Shell y su programación

¡Este material tiene más páginas!

Vista previa del material en texto

Introducción al uso y administración del sistema operativo Linux. Shell y su programación
1. Introducción 
 	 
 Cuando finaliza el arranque del sistema operativo, aparece en pantalla el mensaje login:. Este mensaje procede de la ejecución de un programa: el /bin/login. Si ante la invitación del login tecleamos un nombre de una cuenta de usuario válida, seguida de su correspondiente clave de acceso, si inicia lo que se denomina una sesión. Con el inicio de la sesión comienza a ejecutarse un shell que no se extinguirá hasta que la sesión finalice al teclear uno de los dos comandos internos logout ó exit. 
 Un shell es un intérprete de comandos en UNIX. Es un programa que se encarga de "entender" cuanto se escribe en línea de comandos hasta que se pulsa la teclea INTRO. Si lo que se ha escrito es un comando válido, lo ejecuta. Durante la ejecución de una orden, el shell, se suspende a sí mismo y una vez ha terminado con la orden renace de nuevo para seguir con su tarea de intérprete. Su equivalente en el mundo de DOS/Windows es el command.com. 
 
 Los diferentes comandos que puede aceptar el shell los podemos clasificar en los siguientes tipos: 
a) Comandos internos al mismo shell: cd, set, while do done, etc. 
b) Comandos externos al shell: /bin/ls, /bin/cat, /bin/cp, etc. 
c) Programas binarios (compilados): aplicaciones, programas de usuario, etc. 
d) Programas interpretados: guiones o scripts. 
e) Otro shell que, en este caso, se llamará subshell: /bin/bash, /bin/tcsh, /bin/ash, etc. 
f) Un comando interno que finalice al propio shell: exit o logout. 
 
 En Unix existe más de un shell. En toda instalación de Linux se encuentran disponibles los ya mencionados bash, tcsh y ash. Al iniciar una sesión, en general, se utiliza el bash. Para ver cómo se arranca y detiene, manualmente, un shell puede practicarse con el siguiente ejercicio: 
 
	 
	$ ash --> 
	se inicia un segundo shell (subshell). 
	 
	$ exit 	--> 
	se extingue el subshell anterior. 
	 
	$ tcsh 	--> 
	se inicia otro segundo shell. 
	 
	$ exit 	--> 
	se detiene el anterior. 
	 
	$ bash 	--> 
	se inicia el mismo shell otro vez (shell de nivel2). 
	 
	$ exit 	--> 
	se detiene el shell de nivel 2. 
 	$ exit 	--> 	se detiene el shell de nivel 1 (finaliza la sesión). 
 Nota: El shell bash dispone de una variable de entorno llamada SHLVL, cuyas siglas provienen de shell level en inglés, el cual contiene en un dígito decimal el nivel del shell más anidado que se está ejecutando. Para ver cómo cambia el contenido de esta variable, podemos hacer el siguiente ejercicio práctico: 
	 
	$ echo $SHLVL 
	--> 
	mostrará un 1 
	 
	$ bash 	 
	
	
	 
	$ echo $SHLVL 
	--> 
	mostrará un 2 
	 
	$ bash 
	
	
	 
	$ echo $SHLVL 
	--> 
	mostrará un 3 
	 
	$ exit 
	
	
	 
	$ echo $SHLVL 
	--> 
	mostrará un 2 
 	$ exit 
 
 
 Finalmente resta decir que un shell es también un lenguaje de programación. Sus programas se llaman guiones o scripts y pueden realizar multitud de tareas como se verá más adelante. No es un lenguaje compilado sino interpretado. Por esto no se utiliza en programas largos, pues, podrían resultar de lenta ejecución. El parecido más próximo de un guión, en el mundo DOS/Windows, lo constituyen los archivos por lotes o archivos .BAT. Sin embargo los programas del shell son mucho más potentes que los del command.com debido a que el primero dispone de muchas más sentencias y diversos operadores. En cierto modo, la sintaxis utilizada al programar el shell nos recuerda a menudo la que se emplea en la programación en lenguaje C. 
 
 
2. Las variables de entorno 	 
 	 
 Un proceso se define como un programa cargado en memoria principal (RAM) y un conjunto de variables (variables de entorno) que las utiliza dicho programa para introducir, guardar, procesar o devolver datos. Cuando un shell se carga en memoria también utiliza una parte de la memoria para guardar dichas variables. Cuando se invoca a un subshell, por ejemplo otro bash, en el sistema conviven dos procesos, el proceso "padre" y el proceso "hijo", cada cual con sus variables propias. En este caso tenemos dos procesos y dos espacios en memoria (uno para cada proceso) mientras en el disco tenemos un sólo archivo: el /bin/bash. Las variables de un proceso se pueden clasificar en dos tipos: 
 Variables del sistema o variables predefinidas. Como indica su nombre, pertenecen al sistema y no deben modificarse, a menos que sepamos muy bien qué es lo que hacemos, ya que podemos ocasionar serios problemas de funcionamiento, incluso la detención del sistema. 
 Variables de usuario. Son creadas y utilizadas por el usuario para sus propios fines. Pueden declararse y eliminarse según convenga. 
 
 
2.1. Las variables del sistema 
 
 Como ejercicio veremos algunas variables que pueden resultar de cierto interés. Para imprimir en pantalla el contenido de una variable se utiliza la orden echo seguida de su nombre pero anteponiéndole el $ delante y sin mediar ningún espacio. En general, el nombre, se escribe con mayúsculas. 
 
	 
	$ echo $PWD 
	--> contiene la ruta completa del directorio actual. 
	 
	$ echo $OLDPWD 
	--> contiene la ruta completa del directorio anterior al actual. 
	 
	$ echo $HOME 
	--> contiene el directorio personal del usuario. 
	 
	$ echo $SHELL 
	--> contiene el shell que utiliza el usuario. 
	 
	$ echo $PATH 
	--> muestra las rutas donde el shell busca los programas. 
	 
	$ echo $RANDOM 
	--> imprime un número aleatorio entre 0 y 32767. 
	 
	$ echo $HISTFILE 
	--> archivo que guarda el histórico de comandos del shell. 
	 
	$ echo $HISTSIZE 
	--> tamaño, en órdenes, del archivo histórico de comandos. 
	 
	$ echo $MAIL 
	--> directorio en donde se guarda el correo del usuario. 
	 
	$ echo $PS1 
	--> contenido del prompt del nivel 1 ó prompt string 1. 
	 
	$ echo $PS2 
	--> contenido del prompt del nivel 2. 
 
 Se llama prompt al mensaje que imprime en pantalla el shell cuando está disponible esperando a que se le escriba un comando. Este mensaje es configurable y depende del contenido de la variable PS1. Además de otros posibles caracteres el último, que aparece en la línea de comandos (prompt), es el $ si la sesión la ha iniciado un usuario o el # en el caso de que haya sido el administrador (root) quien lo haya hecho. Cuando un comando ocupa más de una línea, al teclear INTRO, aparece el prompt de segundo nivel que por defecto es el carácter >. Puede modificarse su apariencia cambiando el contenido de la variable PS2. 
 
 Existen otras variables del sistema que se caracterizan por estar formadas por un sólo carácter. Tienen gran interés para la creación de programas del shell. Una de ellas es la ?. La variable ? guarda el entero devuelto por el último programa (u orden) que el shell ha ejecutado. Es la equivalente al ERROLEVEL del DOS/Windows. Cuando la función principal de un programa en C, se ha definido como int main () y en su última línea aparece, por ejemplo, return(25), al terminar de ejecutar este programa, el shell deposita el valor 25 en la variable ?. Por regla general cuando una orden o programa se ejecuta con éxito, devuelve un 0 al shell del sistema operativo. Un ejercicio muy sencillo para practicar la lectura de esta variable es: 
 
	 
	$ echo $? 
	--> 
	Lo más probable es que imprima un 0. 
	 
	$ data 
	--> 
	Comando desconocido, hay un error. El correcto es date. 
	 
	$ echo $? 
	--> 
	Imprime un 127 que es el código de error correspondiente. 
 
 Las demás variables de un sólo carácter son: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, #, *, y @. Funcionan como los parámetros posicionales del DOS. Son muy útiles. Las estudiaremos más adelante. Por el momento, podemos comprobar cómo se escriben y leen. 
 
 	$ set cal 4 2003 --> Escritura. 
	 
	$ echo $0 
	 --> nombre del comando , /bin/bash en donde está set. 
	 
	$ echo $1 
	 --> nombre del primer argumento, cal 
	 
	$ echo $2 
	 --> nombredel segundo argumento, 4 
	 
	$ echo $3 
	 --> nombre del tercer argumento, 2003 
	 
	$ echo $# 
	 --> número total de argumentos, 3 
	 
	$ echo $* 
	 --> imprime todos los argumentos, cal 4 2003 
	 
	$ echo $@ 
	 --> similar al anterior, cal 4 2003 
 
 
2.2. Las variables de usuario 
 
 Para declarar, asignar valor, leer o borrar una variable en un script debemos tener en cuenta lo siguiente: 
Toda variable tiene un nombre y un contenido. Para el nombre se utilizan letras (preferiblemente mayúsculas), dígitos decimales y el signo subrayado. VALOR, MES_3, etc. No se puede poner un dígito decimal como primer carácter. 
No se debe utilizar para nombrar una variable las palabras reservadas, para variables del sistema o para nombrar operadores. (HOME, for, PATH, case, etc.). 
Una variable se declara y se le asigna un valor al mismo tiempo. VALOR=2, MES_3=Marzo, etc. Importante: no dejar espacios a los lados del signo igual. 
Para hacer referencia a su contenido, se utiliza el nombre de la variable precedido por el signo $ y sin espacio de separación. $VALOR, $MES_3, etc. 
Una variable se elimina mediante el comando interno unset del shell seguido de su nombre. Por ejemplo, unset VALOR, unset MES_3, etc. 
Si la variable se quiere utilizar en otro entorno (otro shell) diferente al shell actual debe exportarse al ser declarada. Para ello se utiliza el comando interno export delante de la declaración-asignación de la variable. Ejemplos: export VALOR=10, export MES=Agosto, etc. 
Si se quiere imprimir en pantalla una lista con todas las variables (del sistema y de usuario), previamente exportadas, que hay en un entorno, teclear el comando export sin argumento alguno. 
 
Ejemplos para practicar sobre variables de usuario: 
 
	 
	$ EDAD=25 	 
	--> 
	la declara y le asigna un entero . 
	 
	$ echo $EDAD 	 
	--> 
	para ver su contenido. 
	 
	$ DOMICILIO="San José, 25" 
	--> 
	la declara y le asigna un texto . 
	 
	$ echo $DOMICILIO 	 
	--> 
	para ver su contenido. 
	 
	$ AÑOS=$EDAD 	 
	--> 
	paso de valor entre variables. 
	 
	$ echo $AÑOS 	 
	--> 
	para imprimirlo y verlo. 
	 
	$ PATH=$PATH$HOME:/bin 
	--> 
	ampliar rutas de búsqueda. 
	 
	$ echo $PATH 	 
	--> 
	comprobación de lo anterior. 
	 
	$ YOSOY=$LOGNAME 
	--> 
	lee una variable del sistema 
	 
	$ echo $YOSOY 	 
	--> 
	y la guarda en otra de usuario. 
	 
	$ FECHA=`date` 	 
	--> 
	ejecuta la orden date y 
	 
	$ echo $FECHA 	 
	--> 
	el resultado se asigna a FECHA. 
	 
	$ MISARCHIVOS=`ls -laR | wc -l` --> 
	lista y cuenta los archivos y guarda 
	 
	$ echo $MISARCHIVOS 	--> 
	su número en una variable. 
 
NOTA: La comilla simple aguda ` se obtiene teclando Alt + (96 en el teclado numérico) si estamos en modo comando de línea. Si estamos en un xterm (terminal abierto en un entorno gráfico), se obtiene pulsando dos veces la tecla de la derecha de la letra p (o bien pulsando esta tecla una sola vez seguida de un espacio). Si se omiten estas comillas, el comando no es ejecutado sino tomado como puro texto. 
 
 
2.3. Cómo se envía un grupo de órdenes al shell 
 
 Hasta ahora la operación que con mayor frecuencia se ha realizado ha sido escribir un sólo comando a continuación del prompt y luego INTRO para que se inicie su ejecución. Sin embargo existe la posibilidad de escribir varios comandos en un misma línea, o en varias líneas, y comenzar a ejecutarlos después que se ha terminado de escribir el último. Este grupo de comandos, no es mas que un incipiente programa. Existen varios métodos para hacer esto: 
 	 
 a.- Escribir en una sola línea todos los comandos separados por un ;. Por ejemplo: $ clear ; date ; sleep 5 ; echo FIN ; echo 
 
 b.- Escribir un sólo comando por línea, luego un ; y antes de pulsar INTRO teclear el carácter de escape \ para que el shell "no vea" el fin de línea. El ejemplo anterior se escribiría así: 
 	$ clear ;\ 
 	> date ;\ 
 	> sleep 5 ;\ 
 	> echo FIN ;\ 
 	> echo 
 
 	En este caso el > es el prompt de nivel 2. La barra invertida \ (bakslash) no será necesaria cuando en ese mismo lugar se coloque el carácter de tubería |. 
 	 
 c.- Otro método posible es utilizar un paréntesis que englobe a todos los comandos, escritos, cada uno en una línea, sin necesidad de colocar el ; ni el carácter de escape \ . Se permite incluir líneas de comentario (las precedidas por el carácter #). Además es el procedimiento utilizado para escribir funciones dentro de un script. Continuando con nuestro ejemplo ahora se escribiría así: 
 	$ ( clear 
 	> date 	# esto es un comentario, desde el # hasta el fin de línea. 
 	> sleep 5 
 	> echo FIN 
 	> echo ) 
 
 d.- También se puede utilizar un "documento inserto" para enviar un grupo de órdenes al shell. Debe darse un nombre a dicho documento, por ejemplo DOCUIN, en nuestro ejemplo, poniendo el nombre al comienzo y al final del documento. El documento inserto se comporta como un documento virtual, es decir, no utiliza un archivo en disco propio pues funciona como un "parásito" incrustado dentro de otro archivo real o dentro de un grupo de comandos. El documento inserto debe "leerlo alguien" por ejemplo la orden cat . Las comillas ` ` obligan al shell a ejecutar cada comando entrecomillado. Si no se colocan las comillas, dicho comando, sería tomado como puro texto para imprimirlo en pantalla y nada más. Comprobémoslo con nuestro ejemplo. 
 
 	$ cat <<DOCUIN 
 	> `clear` 
 	> `date` 
 	> `sleep 5` 
 	> `echo FIN` 
> `echo` 
 	> DOCUIN 
 	 
 e.- Finalmente existe la posibilidad de crear un guión como veremos a continuacion. 
 
3. Los guiones o scripts de Unix. 
 	 
 Un script, guión en castellano, no es mas que un archivo de texto sin formato (texto llano) que contiene órdenes o comandos que el shell puede ejecutar. Es parecido a un archivo por lotes .BAT del DOS/Windows. En todo script hay dos fases bien diferenciadas que abordaremos por separado. La primera es la edición y la segunda la ejecución. Una y otra pueden llevarse a cabo utilizando procedimientos diferentes. 
 
3.1. Cómo crear un script. 
 
Para crear un script, podemos seguir tres métodos: 
 	a.- Usar el comando echo y la doble redirección de salida a un archivo, por ejemplo: 
 $ echo clear > script_uno (La primera vez redirección simple para borrar) 
 	$ echo date >> script_uno 
 	$ echo sleep 5 >> script_uno 
 	$ echo echo FIN >> script_uno 	 
 $ echo echo >> script_uno (Por defecto, echo, añade un salto de línea) 
 
 	b.- Utilizar el comando cat y la redirección simple de salida a archivo, es decir:
 	$ cat > script_uno 
 	clear 	date 
 	sleep 5 
 	echo FIN 
 echo (Control +d para finalizar la introducción de texto) 
 
 c.-La forma más usual para crear un script es utilizar un editor de texto llano, por ejemplo el vi. Además, vi, nos permite efectuar cambios sobre un guión, cosa que los comandos echo y cat no permiten. Sin embargo las soluciones anteriores constituyen una posibilidad interesante cuando se presenta el caso de no tener al alcance otro editor más completo y los guiones a realizar no son muy extensos, cosa que en alguna ocasión imprevista síocurre. Utilizando el vi crearemos un segundo guión: 
 
	
	$ vi script_dos 	 
	 (para iniciar el editor vi). 
	 
	i 	 	 
	 (entra en modo inserción, no se imprime la i). 
	 
	clear 	 	 
	 (primera orden del guión). 
	 
	echo El directorio actual es: 
	
	 
	pwd 	 	 
	 (esta orden imprimirá el directorio actual). 
	 
	cd /tmp 	 
	 (y ésta cambiará al subdirectorio /tmp). 
	 
	echo El nuevo directorio es: 
	
	 
	pwd 
	
	 
	echo El directorio final será: 
	 (última orden del guión). 
	 
	ESC 	 	 
	 (pulsar "escape" para regresar al modo orden). 
	 
	:wq 	 	 
	 (para que vi escriba endisco y termine). 
 	 
 	Una vez se ha terminado la edición del guión, podemos ver su contenido tecleando: 
 	$ cat script_dos 
 
 
3.2. Ejecución de un script 
 
 Existen varias maneras de ejecutar un guión. Utilizar una u otra depende de los resultados que deseamos obtener o de la comodidad que perseguimos. Utilizando los dos guiones ya creados, script_uno y script_dos, veremos los diferentes métodos para ejecutarlos. 
 
a) La primera opción es pasarle el guión como argumento a un subshell que "vivirá" el tiempo justo para ejecutarlo. En este caso, el guión, no necesita tener permiso de ejecución. Además los cambios que se producen en el entorno del subshell no se reflejan en el shell actual que lo inició. En nuestro ejemplo del script_dos, observar que al finalizar su ejecución, nos encontramos en el mismo directorio que antes de ejecutarlo pese a que dentro del guión hay un comando para cambiar al directorio /tmp. Para comprobar cómo funcionan nuestros guiones, podemos escribir: 
 	$ sh script_uno 	o 	$ sh /home/usuario1/script_uno 
 	$ sh script_dos 	o 	S sh /home/usuario1/script_dos 
 	 
b) Otro método de ejecución es ponerle el permiso x al guión y escribir su nombre para que lo ejecute el shell actual. Tampoco se reflejan en el entorno actual los cambios producidos durante la ejecución del guión. Al invocar el nombre del guión, debe tenerse en cuenta que en UNIX el directorio actual, por seguridad, no está incluído en las rutas de búsqueda de la variable PATH y por esto el shell "no busca" el nombre de un programa en dicho directorio. Por tanto podemos escribir su ruta de las tres formas siguientes: 
 
 	$ chmod 700 script_uno script_dos (primero, otorgar permisos rwx- - - - - -
). 
 	 
$ /home/usuario1/script_uno 	 	 (ejecutar con ruta absoluta). 
 	$ /home/usuario1/script_dos 
 	 
 $ ./script_uno (ejecutar con ruta relativa). 
 	$ ./script_dos 
 
 	$ script_uno 	 (sólo si su ruta está en la variable PATH). 
 	$ script_dos 
 
 Está claro que la mayoría de las veces resulta más cómodo emplear la última solución expuesta sobre todo cuando el guión ya está terminado y se ha comprobado que su funcionamiento es correcto. Lo más sencillo es copiarlo en el subdirectorio /home/usuario/bin y comprobar que la ruta de este subdirectorio se halla incluída dentro de la variable PATH. De no ser así, utilizar los comandos $ mkdir /home/usuario/bin y PATH=$PATH:/home/usuario/bin en .bashrc. 
 
 
 c) El tercer método para ejecutar un script es utilizar el llamado operador punto .. Consiste en escribir un punto, dejar luego un espacio y teclear luego el nombre del guión. Mediante este método, los cambios del entorno modificado por el guión sí que se mantienen al finalizar su ejecución. En el ejemplo del script_dos se observará que al finalizar, el directorio actual será /tmp. 
En este método, los guiones, no necesitan de permiso de ejecución ni tampoco es necesario que su ruta esté incluída en la variable PATH. Pueden ejecutarse desde el subdirectorio donde se guardan. Comprúebese ejecutando los dos ejemplos. 
 	 	 
 	$ . script_uno 	 (dejar un espacio entre el punto y el nombre). 	$ . script_dos 	 (si no hay espacio se toma como un archivo oculto). 
 
 Otro ejemplo. Utilizando vi, u otro procedimiento de edición, crear un guión llamado script_tres tal que contenga las siguientes sentencias: 
 
 	clear # Borra la pantalla. 	SO="Linux Debian" 	 	 # Se crea la variable SO. 	echo La variable SO contiene: $SO # Muestra el contenido de la variable SO. 
 
 Una vez terminado el script, ejecutarlo empleando la opción sh y la . (punto). Acto seguido visualizar, en ambos casos, el contenido del la variable SO creada por él. 
 
 	$ sh script_tres (el guión imprime el valor de su variable). 	$ echo $SO (no aparece nada pues la variable SO no existe). 
 
 $ . script_tres (el script imprime el valor de su variable). 
 $ echo $SO (vuelve a imprimirse la variable SO, pues sí existe). 
 
 
4. Operadores para programar el shell. 
 
 El shell de Unix dispone de varios operadores formados por una serie de palabras de sintaxis reservada (if, then, fi, do, while, etc.) que permiten construir las estructuras básicas empleadas en programación (secuenciales, condicionales o repetitivas). Estos operadores, al igual que las demás órdenes, pueden teclearse en línea de comandos, a continuación del prompt, o mejor todavía, pueden incluirse dentro de los scripts para darles la categoría de auténticos programas. Describiremos los más importantes 
 
 
4.1. Operador condicional simple (if-then-fi) 
 	 
 Es el si condicional. Este operador evalúa una condición. Si (if) ésta es verdadadera, entonces (then) se ejecuta una orden, o un grupo de órdenes, hasta que aparece el fin (fi) del operador. En el supuesto de que la condición sea falsa, se saltan todos los comandos que hay entre then y fi. Para escribirlo en línea de comandos, o en una sóla línea de un script, se emplea la sintaxis siguiente: 
 	$ if condición ; then ordenes ; fi 	 
 
 Dentro de un programa, o cuando se necesite incluir varias líneas de órdenes, es más cómodo y claro hacerlo de este modo: 
 	 
 	if condición 
 	 	then 	 	 	orden_1 	 	 	orden_2 	 	 	orden_3 	fi 
 	 
 La sintaxis para escribir una condición es: primero escribir el corchete de apertura [, luego dejar un espacio, escribir la condición, dejar otro espacio y por último añadir el corchete de cierre ]. Por ejemplo para comprobar si el contenido de la variable ALFA es igual a cero, se escribiría así: [ $ALFA -eq 0 ]. (eq proviene del inglés equal). Más adelante se verán más tipos de condición. 
 
 Un ejemplo de uso de una estructura condicional simple es el siguiente guión. Lo llamaremos script_if y su contenido será el siguiente: 
 	 	 
 clear # Borramos la pantalla. ALFA=0 # Declaramos ALFA y le asignamos valor 0. if [ $ALFA -eq 0 ] # Comprobamos si es cero. then # Si es verdadera, entonces . . .
 	 	 	echo La variable ALFA contiene un cero 
 	 	 	echo Se ha ejecutado el bloque que sigue a then 
 	fi 
 	echo Fin de la ejecución del script_if 
 
 Lo podemos probar tecleando $ sh script_if . Nos aparecerá en pantalla un mensaje formado por tres líneas de texto. A continuación podemos editarlo y cambiar la segunda línea por ALFA=1. Comprobamos que el resultado será la impresión de un mensaje en pantalla con sólo una línea de texto, el echo que está fuera de la estructura condicional, que se ejecuta siempre e imprime el mensaje "Fin de la ejecución del script_if. 
 
 
4.2. Operador condicional doble (if-then-else-fi) 
 
 Como indica su nombre ofrece dos alternativas asociando a cada una de ellas un grupo de instrucciones diferente. Siempre se ejecutará un grupo de los dos, pero nunca ambos a la vez ni tampoco se dará el caso de que el operador se salte los dos. 
 Si (if) la condición se cumple, entonces (then), se lleva a cabo la primera alternativa, es decir, el shell carga y ejecuta todas las líneas de comandos que hay entre then y else. Luego salta a la línea que sigue a fi. Sin embargo, si (if) la condición no se cumple (else), se pasa a la segunda alternativa en la que el shell directamente carga y ejecuta las órdenes comprendidas entre else y fi. La sintaxis a emplear, en línea de comandos, es: 
 	 
 	$ if condición ; then ordenes_a ; else ordenes_b ; fi 
 	 
 Una forma de practicar lo anterior es hacerel guión script_else cuyo contenido y sintaxis se muestra a continuación. 
 	 
	 
	clear 
	 
	 
	 # Borramos lapantalla. 
	 
	ALFA=0 
	 
	 
	 # Declaramos ALFA y le asignamos valor 0. 
 	if [ $ALFA -eq 0 ] 
 	 	then 
 	 	 	echo La variable ALFA contiene un cero 
 	 	 	echo Se ha ejecutado el bloque que sigue a then 
 	 
 	 	else 
 	 	 	echo La variable ALFA contiene un uno 
 	 	 	echo Se ha ejecutado el bloque que sigue a else 
 	fi 
 	echo Fin de la ejecución del script_else 
 
 Probarlo haciendo $ sh script_else. Acto seguido modificarlo cambiando la segunda línea por ALFA=1 y volver a probarlo contrastando los resultados. 
 
 El procedimiento de reeditar el guión cada vez que deseamos dar un nuevo valor a una variable, no es muy práctico. Esto mismo se puede hacer de modo interactivo. Podemos decirle al shell que se pare y espere a que le demos, a través del teclado, un valor determinado. Con este fin se ha diseñado el comando read, interno al shell. El uso de esta orden queda suficientemente claro en el script_read que aparece a continuación. 
 	 
 	clear 	 	 	 # Borramos lapantalla. 	echo Introduzca un dígito 0 ó 1 	 # Informar al usuario. 	read BETA 	 # Se declara BETA y asigna el bit leído por teclado. 
 	 	if [ $BETA -eq 0 ] # si ha tecleado un 0 entonces. 
 	 	then 
 	 	 	echo La variable BETA contiene un cero 
 	 	 	echo Se ha ejecutado el bloque que sigue a then 	 	else # Si no ha tecleado 0. 
 	 	 	echo La variable BETA contiene un uno 
 	 	 	echo Se ha ejecutado el bloque que sigue a else 
 	fi 
 	 
 	echo Fin de la ejecución del script_read 
 
 
 Observar que la alternativa else se cumple para valores de BETA igual a 1 y muchos otros más. Para ser exactos cualquier valor que no sea 0. Teclear sh script_read para probarlo. 
 
 
4.3. Anidación de operadores if 
 
 Dentro de un primer if, en su bloque de instrucciones que siguen a then o a else, se puede incluir un segundo operador condicional, simple o doble. Diremos, en este caso, que el segundo operador está anidado en el primero. Además esta anidación se puede repetir más veces, dificultando también la legibilidad del programa. La escritura en una sola línea es compleja. Si se escribe dentro de un guión se facilita mucho la lectura si, además, se introduce una tabulación a cada nivel de anidación. No debe olvidarse tampoco que cada if tiene su fi y que conviene escribirlo en la misma columna. Si el operador es doble, cada then tendrá su else, también en la misma columna. 
 Veremos un ejemplo de anidación, a tres niveles, en donde se podrán evaluar hasta tres condiciones diferentes y el shell ejecutará lo que haya escrito en sólo uno de los cuatro bloques de instrucciones del programa. Así, si se cumple la primera condición, se ejecuta el bloque_a de instrucciones y el programa termina. Si no se cumple la primera pero se cumple la segunda condición, se ejecuta el bloque_b de órdenes y finaliza. Si tampoco se cumple la segunda condición, se comprueba la tercera y caso afirmativo se ejecuta el bloque_c y termina. Por último se ejecuta el bloque_d sólo cuando no se ha cumplido ninguna de las tres condiciones anteriores. 
 	 
 Lo llamaremos script_elseif y lo que hará el programa es pedir dos enteros por teclado (ALFA y BETA) para realizar después todas las comparaciones posibles entre ellos mostrando el resultado en pantalla 
 	 
clear 
echo Introduzca un entero de dos dígitos. Le llamaremos ALFA read ALFA 
echo Introduzca otro entero de dos dígitos. Le llamaremos BETA read BETA 
 
if [ $ALFA -gt $BETA ] 
 	then 
	 	 	echo El valor de ALFA es el mayor 	 	echo Ejecutado el bloque_a 	else 
 	 	if [ $ALFA -lt $BETA ] 
	 	 
	then 
	 	 
	 echo El valor de BETA es el mayor 
	 	 
	 echo Ejecutado el bloque_b 
	 	 
	else 
	 	 
	 	if [ $ALFA -eq 0 ] 
	 
	 	 then 
	 
	 	 	echo ALFA y BETA son nulos 
	 
 
	 	 	echo Ejecutado bloque_c 
	 
	 	 else 
	 
	 echo ALFA y BETA son iguales 
	 
	 	 	echo Ejecutado bloque_d 
	 	 
	 	fi 
 	 	fi fi 
 
 Con el fin de simplificar la escritura, cuando un if sigue a un else, se puede utilizarse directamente la contracción elseif. En este caso el fi que complementa al if del elseif, no se pone. 
 
 	ESCRITURA ORIGINAL 	ESCRITURA SIMPLIFICADA else 
 if [ $ALFA -eq 0 ] 	 	 elseif [ $ALFA -eq 0 ] 	 then then 
 echo ALFA y BETA son nulos echo ALFA y BETA son nulos echo Ejecutado bloque_c echo Ejecutado bloque_c 
 else else 
 echo ALFA y BETA son iguales 	 echo ALFA y BETA son iguales 
 echo Ejecutado bloque_d echo Ejecutado bloque_d fi 
 
 
4.4. La orden interna test y el operador if 
 
 El shell contiene un comando interno llamado test que permite realizar múltiples tareas. Por ejemplo comprueba la existencia de variables y puede hacer comparaciones entre su contenido. También busca si existen archivos o directorios y comprueba su tipo, sus permisos, etc. Por tanto ambas órdenes, if y test, forman un conjunto inseparable que facilita en gran medida la construcción de los programas en shell. 
 Existen dos modos de uso de la orden test. El más frecuente es el que emplea un par de corchetes [ ] sin necesidad de escribir la palabra test. En el otro modo, al contrario, se escribe la palabra test y no se ponen los corchetes. Podemos teclearlos directamente, a continuación del prompt, y comprobar que el resultado obtenido es el mismo. Por ejemplo, para ver que la variable HOME existe, usaremos una de estas dos expresiones. 
 	 
	 
	$ if [ $HOME ] ; then echo Existe ; fi 
	--> Imprime en pantalla "Existe" 
	 
	$ if test $HOME ; then echo Existe ; fi 
	--> Imprime en pantalla "Existe"
 	 
 Con independencia del modo sintáctico que empleemos, lo que hace el comando test es poner la variable de entorno ? a 0, cuando la expresión evaluada es cierta, y a 1 si ésta es falsa. Lo podemos ver fácilmente tecleando a continuación del prompt los ejemplos siguientes: 
 
	 
	$ test $PWD ; echo $? 
	--> 	0 (verdad, $PWD existe). 
	 
	$ test $pwd ; echo $? 
	--> 1 por ser falso ($pwd no existe). 
	 
	$ test 4 -gt 3 ; echo $? 
	--> 	0 (pues 4 > 3). 
	 
	$ test ! 5 -eq 5 ; echo $? 
	--> 	1 falso (! niega la condición). 
	 
	$ [ $PWD ] ; echo $? 
	--> 	0 (porque 5 == 5). 
	 
	$ [ $pwd ] ; echo $? 
	--> 	1 (no existe $pwd). 
	 
	$ [ ! $pwd ] ; echo $? --> 
	0 (verdad, pues! niega). 
	 
	$ [ 5 -gt 5 ] ; echo $? 
	--> 	1 ( falso, no es 5 > 5). 
 
 Un ejemplo práctico de guión, en donde se utiliza la orden test, para comprobar la existencia de una variable, es el script_test siguiente: 
 clear# Borrar la pantalla. if test ! $CIUDAD then 
 	 	 	echo La variable CIUDAD no existe pero se va a crear 	 	 	CIUDAD="Castellón de la Plana" 
 	 	 	echo Su contenido actual es $CIUDAD 
 	 	else 
 	 	 	echo La variable CIUDAD ya existe y vale $CIUDAD 
 	fi 
 	echo En todo caso la variable CIUDAD ya está creada 
 
Nota: Comprobar el funcionamiento con . y con sh. Repetir luego declarando la variable con export, es decir, export CIUDAD="Castellón de la Plana" . 	 
 Las principales opciones que acepta la prden test para la comparación del contenido de variables enteras entre sí o con valores constantes son: 
	 
	-eq 
	--> 
	equal 	 
	--> 
	igual que 
	 
	-gt 
	--> 
	greater than 
	--> 
	mayor que 
	 
	-ge 
	--> 
	greater or equal 
	--> 
	mayor o igual que 
	 
	-ne 
	--> 
	not equal 
	--> 
	distinto de 
	 
	-lt 
	--> 
	less than 
	--> 
	menor que 
	 
 
	-le 
	--> 
	less or equal 
	--> 
	menor o igual que 
	 
	Otros argumentos para comprobar la existencia de archivos o directorios, su tipo y los 
permisos que tenemos sobre ellos son: 
	 
	[ -e nombre ] 
	exists 
	--> verdad si "nombre" existe. 
	 
	[ -f nombre ] 
	file 
	--> verdad si existe y es un archivo corriente. 
	 
	[ -d nombre ] 
	directory 
	--> verdad si existe y es un directorio. 
	 
	[ -L nombre ] 
	Link 
	--> verdad si "nombre" es un enlace simbólico. 
	 
	[ -s nombre ] 
	size 
	--> verdad si "nombre" es un archivo no vacío. 
	 
	[ -r nombre ] 
	read 
	--> verdad si tenemos permiso de lectura. 
	 
	[ -w nombre ] 
	write 
	--> verdad si podemos escribir en "nombre ". 
	 
	[ -x nombre ] 
	execute 
	--> verdad si podemos ejecutar "nombre". 
	 
	[ -O nombre ] 
	Owner 
	--> verdad si somos el propietario de "nombre". 
	 
	[ -G nombre ] 
	Group 
	--> verdad si somos del grupo de "nombre". 
 	 
 	 
 	La orden test también puede hacer, sobre los archivos, las averiguaciones siguientes: 
 [ nombre_1 -nt nombre_2 ] near than --> verdad si nombre_1 es más reciente que nombre_2. 
 [ nombre_1 -ot nombre_2 ] old than --> verdad si nombre_1 es más antiguo que nombre_2. 
 	 
 	Finalmente, para el chequeo de cadenas de caracteres, dispone de estas opciones: 
 [ -z cadena ] --> zero verdad si "cadena " está vacía. 
 	[ cadena_1 = cadena_2 ] --> igual verdad si las dos cadenas son iguales. 	[ cadena_1 != cadena_2 ] --> distinta verdad si las son diferentes. 
 
 
Ejemplo de uso de la orden test comparando cadenas de caracteres. Guión script_test_cadena. 	clear 
 	echo Introduzca el nombre de una distribución de un S.O. Linux 
 	read NOMBRE 
 if [ -z $NOMBRE ] then echo Debe teclear algún caracter antes de INTRO. 
 elif [ $NOMBRE="Debian" -o $NOMBRE="debian" ] then echo Ha acertado. Soy Debian. else echo No. Ese no es mi nombre. 
 	fi 
 
NOTA: La opcion -o (-or) realiza la función lógica O, por tanto la condición global es verdadera si lo es alguno de sus miembros encerrados entre corchetes. También está disponible la función lógica Y, que es cierta si los dos miembros son ciertos. Se escribe -a (-and). Por ejemplo para comprobar que existe el directorio /tmp y además saber que éste tiene permiso de acceso, escribiremos: 
 
 	$ [ -d /tmp -a -x /tmp ] 
 	$ echo $? 	--> 	 Escribirá un 0 porque es verdad. 
 
 
4.5. Estructura condicional múltiple (case-in-esac) 
 	 
 Resulta muchas veces un tanto complicado el seguimiento de programas que utilizan varios operadores condicionales anidados. Existe una alternativa, similar a la existente en el lenguaje C, que consiste en hacer uso del operador case interno al shell. Es la mejor herramienta para construir menús de usuario. La sintaxis general que requiere este operador es: 
 
 	case VARIABLE in 	 	PATRON1) orden_1 
 	 	 	 ;; 
 	 	PATRON2) orden_2 
 	 	 	 ;; 
 	 	 *) orden_3 
 ;; 
 	esac 	 
 
 Las palabras reservadas y caracteres necesarios son: case in ) ;; * esac. La variable podrá contener un valor entero o una cadena de texto e incluso un sólo carácter. Cada patrón deberá consistir en una constante entera o en una cadena de texto. Cuando el contenido de la variable y el de un patrón "casan", es decir coinciden, se ejecuta la orden o grupo de órdenes que sigue a ese patrón hasta que aparece la línea con doble punto y coma, la cual provoca un salto incondicional hasta la sentencia que sigue a esac (case al revés). Si no hay coincidencia, la variable se compara con el siguiente patrón. Finalmente el * actúa como un patrón comodín, de modo que el bloque de órdenes asociadas a él sólo se ejecuta cuando ningún patrón anterior ha coincidido con el contenido de la variable. No es obligatorio poner la sección del * pero sí es recomendable hacerlo, por ejemplo en un menú, en donde es útil lanzar un mensaje por pantalla cuando el usuario no ha elegido ninguna de las opciones que se le han propuesto. Cualquier valor de la variable será coincidente con el * razón por la cual éste se sitúa como la última opción del programa. 
 	 
 Se propone, como ejemplo práctico, realizar el guión script_case_mes, cuyo contenido se expone a continuación. 
 	clear echo Introduzca el número de un mes. \(1 al 12\) # Escapar los paréntesis. 	read MES 
 	case $MES in 
	 
	 
	 1) NOMBRE=Enero 
	 
	 
	 DIAS=31 
	 
	 
	 ;; 
	 
	 
	 2) NOMBRE=Febrero 
	 
	 
	 DIAS=28 
 	 ;; 
 	(completar los mesese 3 al 11 con 9 secciones más) 
 	 	12)NOMBRE=Diciembre 
 	 	 DIAS=31 
 ;; 
 	 	 *)NOMBRE=" un mes que no existe." 	 	 unset DIAS 
 	 	 ;; 
 	esac 
 	echo -n El mes $MES es $NOMBRE 
 	if [ $DIAS ] ; then echo " y tiene $DIAS días." ; else echo ; fi 
 	 
 Se permite la utilización de más de un valor, para cada patrón. Estos valores deben separarse usando el carácter | que representa una función O (or) entre los diferentes valores enteros. Por ejemplo, el siguiente guión, script_case_estacion, captura el mes a partir de la fecha del sistema y nos imprime en la pantalla la estación anual en que nos encontramos. (Si quieres que se ejecute de modo automático al iniciar una sesión, escribe en el archivo /home/usuario1/.bashrc una línea con el siguiente comando: sh /home/usuario1/script_case_estación). Reemplaza "usuario1" por el que proceda en cada caso. 
 	clear 
 	MES=`date +%m` # Captura el mes en dos dígitos 
 	case $MES in 
	 	 
	01 | 02 | 03 ) ESTACION=invierno 
	 
	 	 ;; 
	 	 
	04 | 05 | 06 ) ESTACION=primavera 
	 
	 	 ;; 
	 	 
	07 | 08 | 09 ) ESTACION=verano 
	 
	 	 ;; 
	 	 
	10 | 11 | 12 ) ESTACION=otoño 
	 
	 	 ;; 
 esac # El sistema no tiene otros valores que 1 al 12 
 	echo En el mes actual estamos en $ESTACION 
 
 Es cierto que el guión anterior no es muy exacto. Sólo pretende mostrar el uso de | y poco más. Sin embargo sabiendo que la sentencia DIA=`date +%d` asigna a la variable DIA la fecha del día actual empleando dos dígitos, del 01 al 31, un buen ejercicio práctico quese propone es perfeccionarlo considerando las fechas 21 diciembre, 20 de marzo, 21 de junio y 23 de septiembre que, proximadamente, delimitan el cambio de estación . 
 
4.6. Estructura repetitiva "para" (for-in-do-done) 
 
 Como su nombre indica, se utiliza para repetir una sentencia, o un grupo de sentencias, un número determinado de veces, tantas como valores le son asignados a una variable. La sintaxis utilizada en comando de línea es la siguiente: 
 	 
 	$ for VARIABLE in valor1 valor2 valor3 ; do orden u órdenes ; done 
 En este ejemplo la variable VARIABLE tomará, sucesivamente, los valores valor1, 
valor2 y valor3. Para cada uno de estos valores se repetirá el bucle, es decir, se ejecutará la orden (o grupo de órdenes) que aparecen escritas entre do y done. 
 Otros ejemplos para teclear en línea de comandos y comprobar el funcionamiento de este bucle son los siguientes: 
 
 	$ for VARIBLE in 0 1 2 3 4 ; do echo $VARIABLE ; done 
 (imprime 0 1 2 3 4 en una columna). $ for N in 1 2 3 ; do echo Hola mundo ; done 
 (imprime tres líneas "Hola mundo"). 
 	$ for VOCAL in a e i o u ; do echo -n $VOCAL ; done 
 (imprime las vocales en una línea). 
 	$ for DIA in `cal` ; do echo -n $DIA ; done 
 (imprime una línea con los días del mes). 
 	$ for VALOR in ; "esto" es una prueba "de for" ; do echo $VALOR ; done 
 	 	 	 	 	 (imprime 5 líneas de texto). 
 
 El operador for de UNIX se puede anidar constituyendo así una potente herramienta de programación del shell. Si dentro de un bucle for, en las sentencias que hay entre do y done, una de ellas es otro operador for, se dice que el segundo for está anidado en el primero. Si el primero realiza, por ejemplo, cuatro pasadas y el segundo tres, cada sentencia del segundo se ejecutará 12 veces. Un ejemplo: 
$ for DIG in 1 2 3 4 ; do for LET in a b c ; do echo -n " $DIG$LET " ; done ; done 
 
 	Al ejecutarlo debería mostrar: 1a 1b 1c 2a 2b 2c 3a 3b 3c 4a 4b 4c. 
 
 Otro ejemplo práctico, esta vez con tres operadores for anidados, es el guión script_for que se presenta como otro ejercicio más. Observar que la variable de cada bucle sólo tomará los valores 0 y 1 y le daremos un nombre acorde con el peso que después imprimirá (PESO1, PESO2 y PESO4). Por tanto la sentencia echo mostrará 8 valores, en una misma línea, que se corresponderán con los 8 primeros números binarios. (Observar que la opción -n de echo sirve para suprimir el salto de línea). 
 
 	clear # Borrar la pantalla 
 	for PESO4 in 0 1 
 	 	do 
 	 	for PESO2 in 0 1 	 	 	do 
 	 	 	for PESO1 in 0 1 
 	 	 	do 
 	 	 	echo -n " $PESO4$PESO2$PESO1 " 
 	 	 	done 	 	 	done 	 	done 
 	echo # Un salto de línea final 
 
4.7. La orden expr (/usr/bin/expr) 
 
 En realidad, la utilidad expr, no pertenece al shell bash sino que es un programa externo localizado en /usr/bin que se emplea para evaluar expresiones aritméticas sencillas o comparaciones. Es como una calculadora elemental disponible en línea de comandos que opera generalmente con números enteros. 
 
 	Permite evaluar las siguientes operaciones aritméticas: 	suma 	+ 	$ expr 4 + 5 	--> (imprime 9). 	resta 	- 	$ expr 120 - -44 --> (imprime +164). 	producto 	* 	$ expr 12 \* 25 --> (imprime 300). 	cociente 	/ 	$ expr -100 / 3 	--> 	 (imprime -33). 	resto % 	$ expr -100 % 3 	--> 	 (imprime -1). 
 
 Dentro de un guión también puede emplearse expr. Además, el resultado de una operación, puede asignarse a una variable siempre que encerremos entre un par de comillas (simple aguda, Alt 96 decimal) la expresión a evaluar. A su vez, expr, puede operar con valores enteros contenidos en variables. Para que el resultado sea correcto debe respetarse, en la sintaxis, unas reglas muy sencillas: 
Dejar un espacio entre el símbolo de operación y los operandos. 
Utilizar el carácter de escape \ delante del operador producto * y de los paréntesis. 
No dejar espacio entre un entero y su signo, ni entre el paréntesis y su escape, ni a los dos lados del signo igual. 
Aislar, con otro espacio, el par escape-paréntesis de operadores y operandos. 
 	 
 	Podemos teclear secuencialmente los siguientes ejemplos y comprobar los resultados: 
	 
	$ ALFA=`expr 2 + 2` ; echo $ALFA 	 
	--> (imprime 4). 
	 
	$ ALFA=`expr $ALFA + 3` ; echo $ALFA 	 
	--> (imprime 7). 
	 
	$ ALFA=`expr $ALFA + $ALFA` ; echo $ALFA 
	--> (imprime 14). 
 	 	 	 	 	 
 Para que expr resuelva la expresión BETA = 6. (3+4) / 3 . 7 = 2, la escribiríamos así: 
 	$ BETA=`expr 6 \* \( 3 + 4 \) / \( 3 \* 7 \)` ; echo $BETA --> (imprime 
2). 
 
 	También se pueden realizar comparaciones utilizando expr. Los símbolos a emplear son los que se indican a continuación. Daremos un repaso utilizando unos ejemplos. 
	 
	menor que 
	< 
	$ expr 4 \< 5 (verdad, imprime 1).
	 
	menor o igual que 
	<= 
	$ expr -1 \<= -2 (falso, imprime 0).
	 
	igual 	 
	== 
	$ expr 9 == 9 (verdad, imprime 1).
	 
	distinto de 
	!= 
	$ A=`expr 5 != 5` (falso, A valdrá 0).
	 
	mayor o igual que 
	>= 
	$ B=`expr 8 \>= 9` (falso, B valdrá 0).
	 
	mayor que 
	> 
	$ C=`expr -8 \> -9` (cierto, C valdrá 1). 
 
 Observar que expr, en las comparaciones, devuelve un valor a la inversa que test. Por tanto, si en los ejemplos anteriores, consultamos el valor de $?, obtendremos 0 en vez de 1 y viceversa. Finalmente, es interesante, conocer otra de las capacidades que tiene expr en el tratamiento de cadenas. Puede contar el número de caracteres que contiene una variable. La sintaxis y un ejemplo se exponen a continuación: 
 $ IES=Politécnico ; expr length $IES --> (imprimirá 11). 
 
NOTA: A nivel de línea de comandos, cuando expr sea insuficiente, puede utilizarse /usr/bin/bc. Se puede afirmar, con poco margen de error, que bc es un lenguaje de programación porque trabaja con variables de tipo real y con funciones e incluye las estructuras básicas de programación. Por supuesto que no es tan completo como C, pero es una buena solución intermedia entre éste y expr. 
 
 A continuación veremos un ejemplo de integración de expr en bucles for anidados para imprimir una tabla de equivalencias decimal-binario del 0 y 15. Guión script_for_expr. 
 
 	clear 	DECIMAL=0 	for A in 0 1 
 	 do 
 	 for B in 0 1 	 	 do 
 	 	 for C in 0 1 
	 	 
	 do 
	 	 
	 for D in 0 1 
	 	 
	 do 
	 
	 if [ $DECIMAL -le 9 ] ; then echo -n 0 ; fi 
	 
	 echo -n $DECIMAL 
	 
	 echo " en binario es $A$B$C$D" 
	 
	 DECIMAL=`expr $DECIMAL + 1` 
	 	 
	 donedone 
 	 done 
 	done 
 
4.8. Estructura repetitiva "mientras" (while-do-done) 
 
 Comprueba la condición antes de entrar en el bucle. Si ésta se cumple, entonces se ejecuta la orden, ó el grupo de órdenes, que hay escritas entre do y done. A continuación, se vuelve a comprobar la condición que sigue a while y si continúa siendo cierta, el bucle se ejecuta otra vez. El proceso se repite mientras la condición sea cierta. Deberá procurarse que a cada pasada por el bucle se modifique alguna variable, cuyo valor se compruebe en la condición previa a la entrada, para que ésta llegue a ser falsa en algún momento y el bucle termine. De no ser así, el bucle se torna infinito y no acaba nunca. La sintaxis a emplear en la línea de comandos es: 
 
 	$ while condición ; do órdenes ; done 
 
 La sintaxis dentro de un programa script la veremos con un ejemplo. El guión script_while crea 10 subdirectorios, de nombre directorio_00 a directorio_09, dentro del directorio actual y finalmente los muestra listándolos por pantalla. Por supuesto, que los directorios recien creados están vacíos. 
 
 
 NUMERO=0 # Hacer NUMERO igual a 0. while [ $NUMERO -le 9 ] # Mientras sea menor o igual que 9. do mkdir directorio_0$NUMERO # Crearlo. NUMERO=`expr $NUMERO + 1` # Incrementarlo. done 	clear echo Se han creado los directorios siguientes: 
 	ls directorio* 
 
 Ejecutar este guión con las opciones sh script_while y . script_while, comparando los resultados. Los directorios creados no dejarán al guión crearlos de nuevo. Borrarlos con rmdir. 
 
 
4.9. Estructura repetitiva "hasta" (until-do-done) 
 
 Este tipo de bucle es muy parecido al anterior. La única diferencia es que la repetición se efectúa hasta que la condición sea cierta (es decir, mientras sea falsa). Por tanto, si se invierte la lógica de la condición, un bucle "mientras", puede reemplazar perfectamente a otro bucle "mientras". La sintaxis en la línea de comandos es: 
 	 
 	$ until condición ; do órdenes ; done 
 
 Por otra parte, existe un comando externo, /bin/touch, que se utiliza para crear un archivo vacío, es decir de un tamaño de 0 bytes, cuando se le suministra un nombre de un archivo inexistente como argumento. Si el archivo ya existe, le cambia la fecha y la hora por la del sistema sin modificar su contenido. Crear archivos o directorios vacíos es bastante frecuente en UNIX. 
 
 Escribiremos un guión que nos permita crear todos los archivos posibles en un disquete con sistema de archivos FAT 12, hasta agotar las entradas del directorio raíz del mismo. (223, si se le ha puesto nombre al disquete, ya que en DOS/Windows, el LABEL, consume una entrada del total de 224 posibles). 
 
 	if [ ! -d /prueba ] ; then mkdir /prueba ; fi # Crea punto de montaje. 	mount -t msdos /dev/fd0 /prueba # Monta el disquete de MSDOS. 
 	NOMBRE=0 # Segunda parte del nombre del archivo. 
 
 	until [ $? -ne 0 ] # Hasta que la orden touch dé error. ($? no será 0). 	 do 
 	 	NOMBRE=`expr $NOMBRE + 1` 
 	 	touch /prueba/archi$NOMBRE # Crear archivos en disquete. 
 	 done 
 	 
 ls /prueba # Mostrar los archivos creados. umount /prueba # Desmontar disquete. 
 
 Con frecuencia, es muy útil disponer de un archivo con una cantidad exacta de caracteres que nos permita hacer algún tipo de prueba. Se puede hacer un guión, que llamaremos script_bytes, para crear un archivo cuyo nombre, cantidad de caracteres y tipo de carácter contenido se introduzcan por teclado, en modo interactivo, es decir mientras el guión se está ejecutando. 
 	 
 	clear printf "Introduzca el nombre del archivo --> " # Introducir parámetros. read NOMBRE 
 
 	printf "Introduzca la cantidad de caracteres --> " 
 	read CANTIDAD 
 
 	printf "Introduzca el carácter deseado --> " 
 	read CARACTER 
 
 echo -n $CARACTER > $NOMBRE # Borra archivo. Escribe el primer carácter. 
 	while [ $CANTIDAD -gt 1 ] 
 	do 	 	echo -n $CARACTER >> $NOMBRE # Añade un carácter cada vez. 	 	CANTIDAD=`expr $CANTIDAD – 1` # Descontarlo. 
 	done 
 	 
 	echo 	cat $NOMBRE # Imprime el contenido. 	ls -l $NOMBRE # Un listado largo para verlo. 
 
 Ejercicio propuesto: Realiza un programa, de nombre script_tabla9, que imprima en pantalla la tabla de multiplicar del 9. Recuerda que puedes utilizar una de las tres estructuras existentes en el shell; for-in-do-done, while-do-done y until-do-done. 
 
 
4.10. Otras órdenes útiles en bucles (true, false, break, continue, exit) 
 	 
 Las dos órdenes true y false son externas y se encuentran en /bin. La primera de ellas, /bin/true es un script que pone la variable $? a 0 cuando se ejecuta. Hace pues lo mismo que la orden test cuando evalúa una condición verdadera. El programa externo /bin/true tiene un carácter equivalente en el comando interno al shell que hace lo mismo, el : (dos puntos). 
 
 Paralelamente, la orden /bin/false, que también es un guión, cuando se ejecuta pone la variable $? a 1. Ocurre lo mismo que si ejecutamos la conocida secuencia de teclas Control+c. Al evaluar una expresión falsa con la orden interna test ocurrre otro tanto. 
 
 	Teclear en la línea de comandos, lo siguiente: 
	 
	$ true ; echo $? 	 
	--> 
	 (verdad, imprime 0). 
	 
	$ false ; echo $? 	 
	--> 
	 (falso, imprime 1). 
	 
	$ : ; echo $? 	 
	--> 
	 (verdad, imprime 0). 
	 
	$ Control+c ; echo $? 
	--> 
	 (falso, imprime 1). 
	 
	$ [ 5 -eq 5 ] ; echo $? 
	--> 
	 (verdad, imprime 0). 
	 
	$ [ 2 -gt 4 ] ; echo $? 
	--> 
	 (falso, imprime 1). 
 
 Una aplicación usual de true, o de false, es la confección de bucles que en principio parecen infinitos, cuando en realidad son indeterminados en cuanto al número de pasadas que realizarán. Esto viene a decir que no hay ninguna condición de entrada. Sin embargo sí deberá existir una condición de salida para que realmente no se conviertan realmente en infinitos como los dos ejemplos siguientes con los que podemos experimentar. 
 
 	$ while true ; do echo Hola ; done (Control+c para detenerlo). 
 $ until false ; do printf Hola ; done (Control+c para finalizar). 
 
 La orden break es interna al shell /bin/bash. Si se ejecuta dentro de un bucle de tipo for, while o until, rompe el bucle y se ejecuta la primera sentencia que aparece fuera de éste, es decir la que sigue a done. Si la orden break se ejecuta dentro de un bucle anidado, sólo rompe el primer bucle, es decir, el más próximo a ella. La sintaxis de uso, por ejemplo, en bucles de duración indeterminada es: 
 	 
 	$ while true ; do orden1 ; condición ; break ; done 
 	$ until false ; do orden1 ; condición ; break ; done 
 
 Un ejemplo de guión que utiliza bucle for y un break es el script_break que se propone. Observa que el bucle sólo realiza cinco pasadas, de las 10 posibles. 
 	clear 
 	for VALOR in 0 1 2 3 4 5 6 7 8 9 	do 	 	echo -n " $VALOR " # (imprime : 0 1 2 3 4). 
 	 	if [ $VALOR -eq 4 ] ; then break ; fi 	done 	echoLa orden continue es también interna al shell /bin/bash. Si se ejecuta dentro de un bucle de tipo for, while o until, no rompe el bucle. Lo que realmente hace es saltarse todas las sentencias que aparecen entre ésta y done, pero sin salirse del bucle. Si continue se ejecuta dentro de un bucle anidado, sólo afecta el salto al primer bucle más próximo a ella. 
 	 
 Veremos, como ejemplo, el guión script_continue que incluye dos bucles for anidados y una sentencia continue escrita en el bucle más interno. De las 9 pasadas posibles (3 del primero por 3 del segundo) sólo se hacen 6. Elimina la línea que contiene el if, y el continue, y compara el resultado. 
 	 
 	clear 
 	for X in 1 2 3 
 	 	do 
 	 	for Y in a b c 
 	 	do 
 if [ $Y = b ] ; then continue ; fi echo -n " $X $Y " # (imprime: 1a 1c 2a 2c 3a 3c). done 
 	 	done 
 	echo 	 
 
 La orden exit es otro comando interno del shell bash. Es muy flexible porque admite hacer varias cosas. Si se invoca desde dentro de un bucle de cualquier tipo, efectivamente lo termina. Pero exit hace más cosas. En realidad lo que hace es que finaliza el shell que la ejecuta. Por otro lado, se le puede pasar, como argumento, un valor entero que devolverá al "proceso padre" es decir al shell que ha iniciado el shell que ejecuta al guión que contiene a exit. De esta manera, "el proceso padre" podrá "leer" el valor de la variable $? y obtener detalles acerca de cómo se ha desarrollado la ejecución del guión, una vez que haya terminado su trabajo. Observar que el mecanismo que utiliza exit es similar al que emplea la función return() del lenguaje C de programación. 
 
 Pondremos un ejemplo. El guión script_exit, calcula el cuadrado de un entero. Si se introduce un valor fuera del rango admitido, el programa termina y devuelve un código de error 127. Sin embargo si finaliza a petición del usuario, devuelve un código diferente, el 69. Ambos valores son devueltos por exit y pueden leerse haciendo $ echo $? después de finalizar el guión. 
 
 while true # Bucle indeterminado. 
do 
 clear 
 printf "CÁLCULO DE CUADRADOS. (Pulse sólo INTRO para salir) \n" printf "Introduzca un entero de 0 al 99 --> " read ENTERO 
 	 
 if [ -z $ENTERO ] ; then exit 69 ; fi # Si no ha tecleado nada, devuelve 69. 
 if [ $ENTERO -lt -99 -o $ENTERO -gt + 99 ] ; then exit 127 ; fi 
 	 	 	 	 	 	 # Error código 127. 
 	CUADRADO=`expr $ENTERO \* $ENTERO` 
 echo El cuadrado de $ENTERO es $CUADRADO sleep 5 
done 
 
 
4.11. Los parámetros posicionales. Órdenes shift y set 
 
 Los parámetros de posición son un conjunto de variables del sistema que se nombran con 0, 1, 2, 3, 4, 5, 6, 7, 8 y 9. Los valores de estas variables se asignan de modo automático al teclear en línea de comandos una orden, o un guión, seguidos de varios argumentos. Además, estas variables, pueden ser consultadas desde dentro de un guión en ejecución. En general la variable 0 guarda el nombre del programa invocado, la variable 1 el primer argumento pasado, la variable 2 el segundo argumento, etc. Todos los argumentos deben ir separados por espacios y caso de que alguno necesite contener un espacio, se escribirá entre un par de comillas dobles (""). 
 
 Existen más variables del sistema que complementan el uso de los parámetros posicionales. Estas son la # que guarda el número total de argumentos (sin contar el nombre del programa) , la * que guarda todos los argumentos como una simple cadena de texto y la variable @ que contiene casi lo mismo que la *. Como siempre para consultar el valor de cualesquiera de ellas, se debe poner delante un $. Estos ejemplos clarificarán los conceptos anteriores. 
 
 	$ set uno dos tres (no imprime nada, la orden set asigna valores a los parámetros). 
 	$ echo $0 (imprime: /bin/bash porque set es interna al shell). 	$ echo $1 (imprime: uno). 
 	$ echo $2 	 	 (imprime: dos). 
 	$ echo $3 (imprime: tres). 
 	$ echo $# (imprime: 3). 
 	$ echo $* 	 (imprime: uno dos tres). 
 
 En el ejemplo anterior, ha sido la orden interna set la que ha asignado los valores a los parámetros. Sin embargo esto también lo puede hacer un guión cualquiera si tales valores se los pasamos como argumentos, por ejemplo el script_param cuyo listado se muestra a continuación. 
 
 	Para probarlo, teclear $ sh script_param Probando los "parámetros posicionales" 
 
 	clear 
 
 	echo El nombre del guión es: $0 # Imprime: script_param 
 echo El número de argumentos es: $# # Imprime: 3 
 	echo El primer argumento es: $1 # Imprime: Probando 	echo El segundo argumento es: $2 # Imprime: los 	echo El último argumento es: $3 	 # Imprime: parámetros posicionales 
 	 
 	echo Todos los argumentos son: $* # Imprime: Probando los parámetros posiconales 
 
 Pero aún hay más. La orden set es todavía más potente de lo visto hasta ahora. Es capaz de asignar a los parámetros posicionales los datos que resultan al ejecutar una órden o programa cualquiera y que normalmente se envían por defecto a la salida stándar (pantalla). Es como si la salida fuese redireccionada (por set) a los parámetros de posición. Lo único necesario es que existan espacios para poder separar los argumentos. Hay que añadir las comillas ` ` para indicarle al shell que debe ejecutar todo lo entrecomillado antes de que set asigne los resultados. 
 	 
 	Teclear las dos líneas siguientes y mirar luego $1, $2, $3 , etc. 
 
 	$ date --> dia-semana mes dia hora CET año 
 	 	 | | | | | | 
 	$ set `date` --> en $1 en $2 en $3 en $4 en $5 en $6 
 
Otros ejemplos para practicar: 
 	 
 	$ clear ; set `date` ; echo Hoy es $1, dia $3, del mes de $2, del año $6. Son las $4 
 
 	$ set `cal` ; while [ $# -ne 0 ] ; do echo -n "$1 " ; shift ; done ; echo 
 
 	$ clear ; set `fdisk -l | grep hda | grep \*` ; echo Partición activa $1 
 
 	$ clear ; set `ls -a $HOME` ; echo Tiene $# archivos en su directorio personal 
 
 	$ set `date +"%H %M %S"` ; echo Son las $1 horas, $2 minutos, $3 segundos 
 
 El primer ejemplo muestra la fecha en un formato personalizado. El ejemplo segundo toma el calendario del mes actual y todos sus días van "pasando" por $1 y los imprime. El tercero imprime la partición activa de nuestro disco duro. El cuarto nos imprime el número, aproximado, de archivos de nuestro directorio. El último, personaliza la presentación de la hora en pantalla. 
 
 Al ejecutar la orden interna shift se produce un desplazamiento, a la izquierda, de todos los parámetros de posición perdiéndose el contenido del 0 al ser sobreescrito por el 1. Si consultamos el valor de # veremos que se ha decrementado. De esta manera podemos pasar más de 9 argumentos a un guión pues mediante desplazamientos sucesivos podremosacceder a todos ellos. Al comando shift se le puede pasar un argumento, entero y positivo, para indicarle que el desplazamiento sea de dos o más espacios. Podemos comprobarlo con el guión script_shift siguiente: 
 	clear 	until [ $# -eq 0 ] # Hasta que sea cero la variable #. 
 	 do 	 	echo $* -- $# # Mostrar todos los parámetros posicionales. 	 	shift # Hacer un desplazamiento de una posición. 
 	 done 
 
 Ejecutar primero tecleando $ sh script_shift a b c d e f g h i j k l. Luego modificar la penúltima línea del guión poniendo shift 3, en lugar de shift. Volver a ejecutar y observar que ahora los desplazamientos se hacen de 3 en 3. El argumento de shift debe ser menor o igual que el total de argumentos pasados. En el ejemplo anterior, vigilar que el número total de argumentos sea un múltiplo de 3, cuando usamos la sentencia shift 3. 
 
 
5. Utilización de documentos insertos en un script 
 
 
 Un "documento inserto" es una modalidad de archivo que no tiene realidad como archivo pero que es tratado como si lo fuese por las órdenes de UNIX. En realidad, su texto, está "insertado" en el mismo guión, de manera que se tiene un sólo archivo en disco, el cual contiene al guión y al documento inserto. 
 
 También se le llama "documento aquí" y suele caracterizarse porque tiene una cabecera y una cola (con una misma etiqueta para ambos) que lo delimita del resto del guión. Mediante doble redirección de entrada se entrega su contenido a una orden o programa de UNIX. 
 	 
 Aunque no tiene mucho sentido hacer particiones en un disquete, es una forma muy poco arriesgada y muy didáctica de practicar con el programa particionador fdisk de UNIX. Como sabemos, un disquete de 1.44 MB, con formato estándar, tiene 2 cabezas, 80 cilindros y 18 sectores por cilindro. Si deseamos crear una partición primaria, la número 1, desde el cilindro 10, hasta el cilindro 30, deberíamos realizar los siguientes comandos: 
 
 $ fdisk /dev/fd0 (se inicia el fdisk). Command (m for help): n (new, nueva partición). e extended p primary partition (1-4) p (primaria). 
 	Partition number (1-4): 1 	 	 (la número 1). 
 	First cylinder (1-80, default 1): 10 	 	 ( cilindro inicial10). 
 	Last cylinder (11-80, default 80): 30 	 	 (cilindro final 30). 
 	Command (m for help): w 	 (write, el fdisk escribe y sale). 
 	$ 
 
 Todos los comandos orientados al fdisk (n, p, 1, 10, 30 y w) deben ir seguidos de INTRO. Al finalizar el particionado manual, podemos teclear $ fdisk -l /dev/fd0 para obtener una lista de las particiones creadas en el disquete. Nos imprimirá lo siguiente: 
 
 	Disk /dev/fd0: 2 heads, 18 sectors, 80 cylinders 
 	Units = cylinders of 36 * 512 bytes 
 
 	Device Boot Start End Blocks Id System 
 	/dev/fd0p1 10 30 378 83 Linux 
 	 
 Pasemos ahora a realizar la misma tarea utilizando un guión, el script_fdisk, y un documento inserto que llamaremos DOCUFD. (Nótese que deberá suprimirse la partición /dev/fd0p1 antes de poder utilizar de nuevo este guión). La forma de escribirlo es: 
 
 	fdisk /dev/fd0 << DOCUFD 
 	n 	p 	1 
 	10 
 	30 	w 
 	DOCUFD 
 fdisk -l /dev/fd0 # Lista las particiones creadas. 
 
 Otro ejemplo de utilización de un documento inserto es el guión script_vi. Primero crea un archivo en disco (mical) que contiene el calendario del mes actual. Después, el documento inserto DOCUVI entrega órdenes al editor de texto vi que es iniciado por el guión. Las órdenes consisten en decirle a vi que busque en el archivo "mical" el día correspondiente a la fecha actual y cambie el, ó los dos dígitos, por uno ó dos **. Finalmente, el guión imprime el archivo modificado y luego lo borra del disco. Este guión, por exigencias de vi, deberá ejecutarse en un terminal real. 
 	 
 	cal > mical # Crea el archivo en disco mical. 	set `date` # Captura el día en $3. 
 
 	vi mical << DOCUVI 
 	:3,5 s / $3 / * / 
 	:wq 
 	DOCUVI 
 	 
 	clear # Borrar la pantalla. 	cat mical # Imprime el nuevo contenido de mical. 	rm -f mical # Y lo suprime. NOTA: En el guión anterior en las fechas de 2 dígitos, cambiar :3,5 s / $3 / * / por :4,8 s /$3/**/ 
 	 
 El script_vi no tiene mayor interés que mostrar cómo pueden pasarse comandos al editor vi. Otra manera, más eficiente, de resolver el programa anterior es el guión script_día que se expone a continuación. Marca el día de la fecha sobre el calendario del mes actual reemplazando el dígito (o los dos dígitos) por un asterisco (o por dos asteriscos) de modo automático. Si en el archivo .bashrc incluímos la línea sh script_día (o mejor sh /home/usuario1/bin/script_dia), cada vez que iniciemos una sesión, nos aparecerá en pantalla el calendario con las marcas elegidas y en el lugar preciso. 
 
 	clear 	set `date` # Captura en $3 la fecha del sistema. 
 if [ $3 -lt 10 ] # Si el día es de un dígito. then 
 cal | sed "3,5 s /$/ /" | sed "3,5 s / $3 / * /" # Las fechas de un dígito están en las líneas 3 a 5 (un *) 
 
 	 	else 
 	 	 	cal | sed "4,8 s /$3/**/" 
 	 	 	# Las fechas de 2 dígitos están en las líneas 4 a 8 (dos **) 
 	fi 
 
NOTA: En las fechas de un sólo dígito, si aparecen al final de la línea, debe añadirse un espacio. Para esto se coloca el primer filtro sed. Observar que $3 y el * tienen un espacio a cada lado. 
 
6. Utilización de funciones dentro de un script 
 
 Como es de esperar, en un guión, pueden incluirse funciones. Esto aporta dos ventajas: la primera es la modularización del programa, mejorando la lectura y comprensión del mismo y reduciendo las sentencias a escribir, y la segunda es el incremento en la velocidad de ejecución del mismo porque las funciones se cargan en memoria antes de poder ser ejecutadas dado que el guión es un programa interpretado y no compilado. Para escribir una función deben tenerse en cuenta los siguientes detalles: 
 
· La sintaxis, que es prácticamente la misma que la utilizada en el lenguaje C. 
· El declarar y definir la función al principio del guión ó antes de ser utilizada. 
· Los argumentos pasados al llamar a la función, se hacen a través de parámetros de posición, separados por espacios, ($1, $2, $3, etc). 
· Las variables que utilizan las funciones son de tipo global y pueden ser "vistas" por el módulo principal, pero no a la inversa pues dependerá del orden en que han sido creadas dentro del guión. 
 
 Haremos un guión en el que introducimos un entero positivo, a través del módulo principal, lo pasamos a la función "binariza()" para que nos lo ponga en binario y finalmente lo pasamos a la función "imprime()" para que lo muestre en pantalla. El algoritmo de conversión del decimal al binario consiste en restar sucesivamente los pesos 128, 64, 32, 16, 8, 4, 2 y 1. 
 
#---------------------------------------------------------------------------------------------------------------------- 	binariza ()# Definición de la función "binariza()". 
 	 { 
 	 DECIMAL=$1 
 	 	 for PESO in 128 64 32 16 8 4 2 1 	 	 do 	 if [ $DECIMAL -ge $PESO ] 
	 	 
	 then 
	 
	 DECIMAL=`expr $DECIMAL - $PESO` 
	 
	 	BIT=1 
	 	 
	 else 
	 
	 	BIT=0 
	 	 
	 fi 
 	 	 BINARIO=" $BINARIO $BIT" # Los bits espaciados. done 
 } 
 	 
 	#------------------------------------------------------------------------------------------------------- 	imprime () # Definición de la función "imprime()". 
 	 { 
 echo El decimal $ENTERO es el binario $* 
 } 
 
 	#------------------------------------------------------------------------------------------------------- 	clear # Definición del cuerpo principal del programa. printf "Introduzca un entero positivo menor que 256 --> " 
 	read ENTERO 
 	 if [ $ENTERO -ge 0 -a $ENTERO -le 255 ] # Si está dentro del rango. then binariza $ENTERO # Se le pasa un argumento. imprime $BINARIO # Se le pasan 8 argumentos. exit 0 # Salida con éxito. else echo El entero $ENTERO está fuera de rango. exit 127 # Salida con error. 
 	fi 
 #------------------------------------------------------------------------------------------------------- 
 
 
Ejercicio propuesto: A partir del guión anterior construye otro, script_funcion_dos, que haga el mismo trabajo pero ahora el proceso de lectura por teclado del valor de la variable NUMERO, lo hará una tercera función de nombre "lee()" que será llamada, antes de todas, por el módulo principal. 
7. Programación de tareas con un script (orden at) 
 
 
 En UNIX, a menudo es necesario, programar diversas tareas para que se ejecuten a ciertas horas del día en las que la carga del sistema, de la red ó del subsistema de impresión, es baja. Es también probable que, a esas horas, no haya personal disponible para enviarle trabajos al ordenador, incluso es posible que la tarea en sí sea detener el sistema. Para solventar estas situaciones existe una utilidad muy flexible que es el programa /usr/bin/at. Una traducción aceptada de at es a las porque, en general, a at, se le deben decir dos cosas: primero qué es lo que tiene que hacer y segundo a qué horas debe hacerlo. 
 
 La tarea, o tareas, que debe iniciar at deben escribirse en un guión. La hora en que deben realizarse se le pasa a at mediante un argumento. Los trabajos que recibe at quedan ordenados cronológicamente y numerados, según el momento de su envío, en el archivo /var/spool/at/jobs, u otro archivo similar. Puede verse la lista de trabajos pendientes y se puede suprimir cualquiera de ellos, si se llega a tiempo porque una vez se ha ejecutado un trabajo, at, lo elimina de la lista de espera. 
 	 
 Normalmente, esta orden, está reservada para root pero se puede crear una lista de usuarios que tengan autorización, ó prohibición, para usarla en /etc/at/allow. También se puede enviar un trabajo para at dentro de una línea del guión que el propio at va a ejecutar para así reprogramar automáticamente los trabajos de ejecución periódica. 
 
Un resumen de las formas de sintaxis admitida por at es la siguiente: 
 	 
 $ at hh:mm < script (Ejecuta el programa script a las hh horas, mm minutos). 
 	$ at hh:mm -f script (Idem al anterior). 
 	$ at now < script (Ahora mismo. Sirve para probarlo). 
 $ at noon < script (A las 12:00 de hoy, mediodía). 
 	$ at midnight < script ( A las 00:00 de mañana, medianoche). 
 	$ at 21:45 today < script 
 	$ at 06:30 tomorrow < script 
 	$ at 23:59 12/31/03 < script (Un minuto antes de tomar las uvas del 2004). 
 	$ at -l 	 (-l list). (Lista trabajos pendientes). 	$ atq 	 (q queue). (Lista trabajos pendientes. Es un alias del anterior). 
 	$ at -d numero (-d delete). (Borra trabajo "numero"). 	$ atrm numero (rm remove). (Borra trabajo "numero". Es un alias del anterior). 
 
 
 	Veremos a continuación unos ejemplos prácticos de uso de esta potente utilidad. El primero de ellos consiste simplemente en generar una tanda de 5 pitidos en el altavoz del ordenador. Crearemos un guión, que llamaremos script_beep con el siguiente contenido: 
 	 for X in 0 1 2 3 4 # Un bucle de 5 pasadas. do echo -e -n "\007" # Un pitido al altavoz. sleep 1 # Esperar un segundo. done 
 	 
 Recordar que el carácter especial 007 decimal corresponde al beep del ordenador y que el 007 decimal equivale también al 007 octal. La orden echo con el argumento -e (-e especial carácter) acepta caracteres en octal. La opción -n suprime el salto de línea para no mover el cursor de la pantalla, cosa que podría resultar molesta. Ejecutar el programa probando varias posibilidades, por ejemplo: $ at now < script_beep o $ at now -f script_beep o $ at hh:mm -f script_beep. 
 	 
 Un segundo ejemplo de guión para ser ejecutado en un tiempo programado, utilizando at, es el script_file que nos crea un subdirectorio de nombre "midirectorio" y dentro de él crea un archivo de nombre "calendario", mediante redireccionamiento, correspondiente al calendario anual del año 2003. Su contenido es muy sencillo. 
 if [ ! -d midirectorio ] # Si no existe. then mkdir midirectorio # Crea el subdirectorio. 
 	fi 	cal 2003 > midirectorio/calendario # Siempre crea el archivo. 
 Para probar su funcionamiento, mirar la hora actual del sistema (tecleando $ date), programarlo para unos minutos más tarde ($ at hh:mm -f script_file ) y de vez en cuando mirar el archivo para ver si ya se ha creado ($ cat midirectorio/calendario). Durante la espera, podemos mirar la cola de trabajos de at ($ at -l) y tomar nota del número de trabajo asignado. Una vez creado, podemos verificar la fecha del archivo ($ ls -l midirectorio/calendario) y mirar, de nuevo, la cola de trabajos ($ atq) para cerciorarnos de que ya no está en espera. Podemos ensayar también cómo suprimir el trabajo ($ atrm numero) antes de que se ejecute . 
 
 Un guión muy simple para apagar el ordenador, por ejemplo a las 23:00 de cada día, es el script_halt que contiene sólo las dos líneas siguientes: 
 	 
 shutdown -h now # Apagar ahora mismo. at 23:00 tomorrow -f script_halt # Reprogramar para mañana. 
 
 	El primer día deberá teclearse: $ at 23:00 today -f script_file 
 
 Por último, si disponemos