El núcleo del
Sistema Operativo
El núcleo
del sistema operativo Unix (llamado Kernel) es un programa escrito casi en su
totalidad en lenguaje C, con excepción de una parte del manejo de
interrupciones, expresada en el lenguaje ensamblador del procesador en el que
opera.
Las
funciones del núcleo son permitir la existencia de un ambiente en el que sea
posible atender a varios usuarios y múltiples tareas en forma concurrente,
repartiendo al procesador entre todos ellos, e intentando mantener en grado óptimo
la atención individual.
El
Kernel opera como asignador de recursos para cualquier proceso que necesite
hacer uso de las facilidades de cómputo. Es el componente central de Unix y
tiene las siguientes funciones:
-
Creación de procesos, asignación de tiempos de atención y sincronización.
-
Asignación de la atención del procesador a los procesos que lo requieren.
-
Administración de espacio en el sistema de archivos, que incluye: acceso,
protección y administración de usuarios; comunicación entre usuarios v entre
procesos, y manipulación de E/S y administración de periféricos.
-
Supervisión de la transmisión de datos entre la memoria principal y los
dispositivos periféricos.
El
Kernel reside siempre en la memoria central y tiene el control sobre la
computadora, por lo que ningún otro proceso puede interrumpirlo; sólo pueden
llamarlo para que proporcione algún servicio de los ya mencionados. Un proceso
llama al Kernel mediante módulos especiales conocidos como llamadas al sistema.
El
Kernel consta de dos artes principales: la sección de control de procesos y la
de control de dispositivos. La primera asigna recursos, programas, procesos y
atiende sus requerimientos de servicio; la segunda, supervisa la transferencia
de datos entre la memoria principal y los dispositivos periféricos. En términos
generales, cada vez que algún usuario oprime una tecla de una terminal, o que
se debe leer o escribir información del disco magnético, se interrumpe al
procesador central y el núcleo se encarga de efectuar la operación de
transferencia.
Cuando
se inicia la operación de la computadora, debe cargarse en la memoria una copia
del núcleo, que reside en e] disco magnético (operación denominada
bootstrap). Para ello, se deben inicializar algunas interfaces básicas de
hardware; entre ellas, el reloj que proporciona interrupciones periódicas. El
Kernel también prepara algunas estructuras de datos que abarcan una sección de
almacenamiento temporal para transferencia de información entre terminales y
procesos, una sección para almacenamiento de descriptores de archivos y una
variable que indica la cantidad de memoria principal.
A
continuación, el Kernel inicializa un proceso especial, llamado proceso 0. En
general, los procesos se crean mediante una llamada a una rutina del sistema
(fork), que funciona por un mecanismo de duplicación de procesos. Sin embargo,
esto no es suficiente para crear el primero de ellos, por lo que el Kernel
asigna una estructura de datos y establece apuntadores a una sección especial
de la memoria, llamada tabla de procesos, que contendrá los descriptores de
cada uno de los procesos existentes en el sistema.
Después
de haber creado el proceso 0, se hace una copia del mismo, con lo que se crea el
proceso 1; éste muy pronto se encargará de "dar vida" al sistema
completo, mediante la activación de otros procesos que también forman parte
del núcleo. Es decir, se inicia una cadena de activaciones de procesos, entre
los cuales destaca el conocido como despachador, o scheduler, que es el
responsable de decidir cuál proceso se ejecutará y cuáles van a entrar o
salir de la memoria central. A partir de ese momento se conoce el número 1 como
proceso de inicialización del sistema, init.
El
proceso init es el responsable de establecer la estructura de procesos en Unix.
Normalmente, es capaz de crear al menos dos estructuras distintas de procesos:
el modo monousuario y el multiusuario. Comienza activando el intérprete del
lenguaje de control (Shell) en la terminal principal, o consola, del sistema y
proporcionándole privilegios de "superusuario". En la modalidad de un
solo usuario la consola permite iniciar una primera sesión, con privilegios
especiales, e impide que las otras líneas de comunicación acepten iniciar
sesiones nuevas. Esta modalidad se usa con frecuencia para revisar y reparar
sistemas de archivos, realizar pruebas de funciones básicas del sistema y para
otras actividades que requieren uso exclusivo de la computadora.
Init
crea otro proceso, que espera pacientemente a que alguien entre en sesión en
alguna línea de comunicación. Cuando esto sucede, realiza ajustes en el
protocolo de la línea y ejecuta el programa login, que se encarga de atender
inicialmente a los nuevos usuarios. Si la clave del usuario, y la contraseña
proporcionadas son las correctas, entonces entra en operación el programa
Shell, que en lo sucesivo se encargará de la atención normal del usuario que
se dio de alta en esa terminal.
A
partir de ese momento el responsable de atender al usuario en esa terminal es el
intérprete Shell.
Cuando
se desea terminar la sesión hay que desconectarse de Shell (y, por lo tanto, de
Unix), mediante una secuencia especial de teclas (usualmente. < CTL > -
D). A partir de ese momento la terminal queda disponible para atender a un nuevo
usuario.
Administración de Archivos y Directorios
El
sistema de archivos de Unix; esta basado en un modelo arborescente y recursivo,
en el cual los nodos pueden ser tanto archivos como directorios, y estos últimos
pueden contener a su vez directorios o subdirectorios. Debido a esta filosofía,
se maneja al sistema con muy pocas órdenes, que permiten una gran gama de
posibilidades. Todo archivo de Unix está controlado por múltiples niveles de
protección, que especifican los permisos de acceso al mismo. La diferencia que
existe entre un archivo de datos, un programa, un manejador de entrada/salida o
una instrucción ejecutable se refleja en estos parámetros, de modo que el
sistema operativo adquiere características de coherencia y elegancia que lo
distinguen.
La
raíz del sistema de archivos (conocida como root ) se denota con el símbolo
“/”, y de ahí se desprende un conjunto de directorios que contienen todos
los archivos del sistema de cómputo. Cada directorio, a su vez, funciona como
la subraíz de un nuevo árbol que depende de él y que también puede estar
formado por directorios o subdirectorios y archivos. Un archivo siempre ocupará
el nivel más bajo dentro del árbol, porque de un archivo no pueden depender
otros; si así fuera, sería un directorio. Es decir, los archivos son como las
hojas del árbol.
Se
define en forma unívoca el nombre de todo archivo (o directorio) mediante lo
que se conoce como su trayectoria (path name): es decir, el conjunto completo de
directorios, a partir de root (/), por los que hay que pasar para poder llegar
al directorio o archivo deseado. Cada nombre se separa de los otros con el símbolo
/, aunque tan sólo el primero de ellos se refiere a la raíz.
Por
ejemplo, el archivo
u/gerencia/abril94l/carta2
tiene
toda esta trayectoria como nombre absoluto, pero se llama
gerencia/abril94l/carta2, sin 1ra diagonal inicial, si se observa desde el
directorio /u. Para los usuarios que están normalmente en el directorio
/u/gerencia, el archivo se llama abril94l/carta2. Así, también puede existir
otro archivo llamado carta2, pero dentro de algún otro directorio y en caso de
ser necesario se emplearía el nombre de la trayectoria (completa o en partes,
de derecha a izquierda) para distinguirlos. Unix ofece medios muy sencillos para
colocarse en diferentes puntos del árbol que forma el sistema de archivos, que
para el ejemplo anterior podría ser el siguiente:
Como
se dijo antes, desde el punto de vista del directorio abril94, que a su vez
pertenece al directorio gerencia del directorio /u, basta con el nombre carta2
para apuntar al archivo en cuestión.
En
esta forma se maneja el sistema completo de archivos y se dispone de un conjunto
de órdenes de Shell (además de múltiples variantes) para hacer diversas
manipulaciones, como crear directorios, moverse dentro del sistema de archivos,
copiarlos, etcétera.
Unix
incluye, además, múltiples esquemas para crear, editar y procesar documentos.
Existen varios tipos de editores, formadores de textos, macroprocesadores para
textos, formadores de tablas, preprocesadores de expresiones matemáticas y un
gran número de ayudas y utilerías diversas, que se mencionan más adelante.
A
continuación se describe el modo de funcionamiento de Unix, con base en un
modelo de estudio de sistemas operativos que lo divide en "capas" jerárquicas
para su mejor comprensión.
Manejo de archivos y de información
Como
ya se describió, la estructura básica del sistema de archivos es jerárquica,
lo que significa que los archivos están almacenados en varios niveles. Se puede
tener acceso a cualquier archivo mediante su trayectoria, que especifica su
posición absoluta en la jerarquía, y los usuarios pueden cambiar su directorio
actual a la posición deseada. Existe también un mecanismo de protección para
evitar accesos no autorizados. Los directorios contienen información para cada
archivo, que consiste en su nombre y en un número que el Kernel utiliza para
manejar la estructura interna del sistema de archivos, conocido como el nodo-i.
Hay un nodo-i para cada archivo, que contiene información de su directorio en
el disco, su longitud, los modos y las fechas de acceso, el autor, etc. Existe,
además, una tabla de descriptores de archivo, que es una estructura de datos
residente en el disco magnético, a la que se tiene acceso mediante el sistema
mencionado de E/S por bloques.
El
control del espacio libre en el disco se mantiene mediante una lista ligada de
bloques disponibles. Cada bloque contiene la dirección en disco del siguiente
bloque en la cadena. El espacio restante contiene las direcciones de grupos de
bloques del disco que se encuentren libres. De esta forma, con una operación de
E/S, el sistema obtiene un conjunto de bloques libres y un apuntador para
conseguir más.
Las
operaciones de E/S en archivos se llevan a cabo con la ayuda de la
correspondiente entrada del nodo-i en la tabla de archivos del sistema. El
usuario normalmente desconoce los nodos-i porque las referencias se hacen por el
nombre simbólico de la trayectoria. Los procesos emplean internamente funciones
primitivas (llamadas al sistema) para tener acceso a los archivos; las más
comunes son open, creat, read, write, seek, close y unlink, aunque sólo son
empleadas por los programadores, no por los usuarios finales del sistema.
Toda
esta estructura física se maneja "desde afuera" mediante la filosofía
jerárquica de archivos y directorios ya mencionada, y en forma totalmente
transparente para el usuario. Además, desde el punto de vista del sistema
operativo, un archivo es muy parecido a un dispositivo.
Las
ventajas de tratar a los dispositivos de E/S en forma similar a los archivos
normales son múltiples: un archivo y un dispositivo de E/S se tornan muy
parecidos; los nombres de los archivos y de los dispositivos tienen la misma
sintaxis y significado, así que a un programa que espera un nombre de archivo
como parámetro puede dársele un nombre de dispositivo (con esto se logra
interacción rápida y fácil entre procesos de alto nivel).
El
sistema Unix ofrece varios niveles de protección para el sistema de archivos,
que consisten en asignar a cada archivo el número único de identificación de
su dueño, junto con nueve bits de protección, que especifican permisos de
lectura, escritura y ejecución para el propietario, para otros miembros de su
grupo (definido por el administrador del sistema) y para el resto de los
usuarios. Antes de cualquier acceso se verifica su validez consultando estos
bits, que residen en el nodo-i de todo archivo. Además, existen otros tres bits
que se emplean para manejos especiales, relacionados con la clave del
superusuario.
Otra
característica de Unix es que no requiere que el conjunto de sistemas de
archivos resida en un mismo dispositivo.
Es
posible definir uno o varios sistemas "desmontables", que residen físicamente
en diversas unidades de disco. Existe una orden (mkfs) que permite crear un
sistema de archivos adicional, y una llamada al sistema (mount) con la que se añade
(y otra con la que se desmonta) uno de ellos al sistema de archivos global.
EI
control de las impresoras de una computadora que funciona con el sistema
operativo Unix consiste en un subsistema (SPOOL) que se encarga de coordinar los
pedidos de impresión de múltiples usuarios. Existe un proceso de Kernel que en
forma periódica revise las colas de servicio de las impresoras para detectar la
existencia de pedidos e iniciar entonces las tareas de impresión. Este tipo de
procesos, que son activados en forma periódica por el núcleo del sistema
operativo, reciben en Unix el nombre de daemons (duendes), tal vez porque se
despiertan y aparecen sin previo aviso. Otros se encargan de activar procesos en
tiempos previamente determinados por el usuario, o de escribir periódicamente
los contenidos de los buffers de memoria en el disco magnético.
Procesos. Manejo del
Procesador
En
Unix se ejecutan programas en un medio llamado "proceso de usuario".
Cuando se requiere una función del Kernel, el proceso de usuario hace una
llamada especial al sistema y entonces el control pasa temporalmente al núcleo.
Para esto se requiere de un conjunto de elementos de uso interno, que se
mencionan a continuación.
Se
conoce como imagen a una especie de fotografía del ambiente de ejecución de un
proceso, que incluye una descripción de la memoria, valores de registros
generales, status de archivos abiertos, el directorio actual, etcétera. Una
imagen es el estado actual de una computadora virtual, dedicada a un proceso en
particular.
Un
proceso se define como la ejecución de una imagen. Mientras el procesador
ejecuta un proceso, la imagen debe residir en la memoria principal; durante la
ejecución de otros procesos permanece primera en la memoria principal a menús
que la aparición de un proceso activo de mayor prioridad la obligue a ser
copiada al disco, como ya se dijo.
Un
proceso puede encontrarse en uno de varios estados: en ejecución; listo para
ejecutar, o en espera.
Cuando
se invoca una función del sistema, el proceso de usuario llama al Kernel como
subrutina. Hay un cambio de ambientes y, como resultado, se tiene un proceso del
sistema. Estos dos procesos son dos fases del mismo original, que nunca se
ejecutan en forma simultánea.
Existe
una tabla de procesos que contiene una entrada por cada uno de ellos con los
datos que requiere el sistema:
identificación,
direcciones de los segmentos que emplea en la memoria, información que necesita
el scheduler y otros. la entrada de la tabla de procesos se asigna cuando se
crea el proceso y se libera cuando éste termina.
Para
crear un proceso se requiere la inicialización de una entrada en la tabla, así
como la creación de segmentos de texto y de datos. Además, es necesario
modificar la tabla cuando cambia el estado del proceso o cuando recibe un
mensaje de otro (para sincronización, por ejemplo). Cuando un proceso termina,
su entrada en la tabla se libera y queda otro disponible para que otro nuevo la
utilice.
En
el sistema operativo Unix los procesos pueden comunicarse internamente entre sí,
mediante el envío de mensajes o señales. El mecanismo conocido como
interconexión (pipe) crea un canal entre dos procesos mediante una llamada a
una rutina del Kernel, y se emplea tanto para pasar datos unidireccionalmente
entre las imágenes de ambos, como para sincronizarlos, ya que si un proceso
intenta escribir en un pipe ocupado, debe esperar a que el receptor lea los
datos pendientes. Lo mismo ocurre en el caso de una lectura de datos
inexistentes: el proceso que intenta leer debe esperar a que el proceso
productor deposite los datos en el canal de intercomunicación.
Entre
las diferentes llamadas al sistema para el manejo de procesos que existen en
Unix están las siguientes, algunas de las cuales ya han sido mencionadas: fork
(sacar una copia a un proceso); exec (cambiar la identidad de un proceso); kill
(enviar una señal a un proceso); signal (especificar la acción por ejecutar
cuando se recibe una señal de otro proceso), y exit (terminar un proceso).
Dentro
de las tareas del manejo del procesador destaca la asignación dinámica
(scheduling), que en Unix resuelve el scheduler mediante un mecanismo de
prioridades. Cada proceso tiene asignada una prioridad; las prioridades de los
procesos de usuario son menores que la más pequeña de un proceso del sistema.
El
"motor" que mantiene en movimiento un esquema de multiprogramación
es, por un lado, el conjunto de interrupciones que genera el desempeño de los
procesos y, por otro, los constantes recordatorios que hace el reloj del
procesador para indicar que se terminó la fracción de tiempo dedicada a cada
proceso.
En
el sistema Unix, las interrupciones son causadas por lo que se conoce como
eventos, entre los cuales se consideran: la ejecución de una tarea de
entrada/salida; la terminación de los procesos dependientes de otro; la
terminación de la fracción de tiempo asignada a un proceso, y la recepción de
una señal desde otro proceso.
En
un sistema de tiempo compartido se divide el tiempo en un determinado número de
intervalos o fracciones y se asigna cada una de ellas a un proceso. Además Unix
toma en consideración que hay procesos en espera de una operación de E/S y que
ya no pueden aprovechar su fracción. Para asegurar una distribución adecuada
del procesador entre los procesos se calculan dinámicamente las prioridades de
estos últimos, con el fin de determinar cuál será el proceso que se ejecutará
cuando se suspenda el proceso activo actual.
Manejo De Memoria
Dependiendo
de la computadora en la que se ejecute, Unix utiliza dos técnicas de manejo de
memoria: swapping y memoria virtual.
Lo
estándar en Unix es un sistema de intercambio de segmentos de un proceso entre
memoria principal y memoria secundaria, llamado swapping lo que significa que se
debe mover la imagen de un proceso al disco si éste excede la capacidad de la
memoria principal, y copiar el proceso completo a memoria secundaria. Es decir,
durante su ejecución, los procesos son cambiados de y hacia memoria secundaria
conforme se requiera.
Si
un proceso necesita crecer, pide más memoria al sistema operativo y se le da
una nueva sección, lo suficientemente grande para acomodarlo. Entonces, se
copia el contenido de la sección usada al área nueva, se libera la sección
antigua y se actualizan las tablas de descriptores de procesos. Si no hay
suficiente memoria en el momento de la expansión, el proceso se bloquea
temporalmente y se le asigna espacio en memoria secundaria. Se copia a disco y,
posteriormente, cuando se tiene el espacio adecuado - lo cual sucede normalmente
en algunos segundos - se devuelve a memoria principal.
Está
claro que el proceso que se encarga de los intercambios entre memoria y disco
(llamado swapper) debe ser especial y jamás podrá perder su posición
privilegiada en la memoria central. El Kernel se encarga de que nadie intente
siquiera interrumpir este proceso, del cual dependen todos los demás. Este es
el proceso 0 mencionado antes. Cuando se decide traer a la memoria principal un
proceso en estado de "listo para ejecutar", se le asigna memoria y se
copian allí sus segmentos. Entonces, el proceso cargado compite por el
procesador con todos los demás procesos cargados. Si no hay suficiente memoria,
el proceso de intercambio examine la tabla de procesos para determinar cuál
puede ser interrumpido y llevado al disco.
Hay
una pregunta que surge entonces es ¿cuál de los posibles procesos que están
cargados será desactivado y cambiado a memoria secundaria? Los procesos que se
eligen primero son aquellos que están esperando operaciones lentas (E/S), o que
llevan cierto tiempo sin haberse movido al disco. La idea es tratar de repartir
en forma equitativa las oportunidades de ejecución entre todos los procesos,
tomando en cuenta sus historias recientes y sus patrones de ejecución.
Otra
pregunta es ¿cuál de todos los procesos que están en el disco será traído a
memoria principal?. La decisión se toma con base en el tiempo de residencia en
memoria secundaria. El proceso más antiguo es el que se llama primero, con una
pequeña penalización para los grandes.
Cuando
Unix opera en máquinas más grandes, suele disponer de manejo de memoria de
paginación por demanda. En algunos sistemas el tamaño de la página en Unix es
de 512 bytes; en otros, de 1024. Para reemplazo se usa un algoritmo que mantiene
en memoria las páginas empleadas más recientemente.
Un
sistema de paginación por demanda ofrece muchas ventajas en cuanto a
flexibilidad y agilidad en la atención concurrente de múltiples procesos y
proporciona, además, memoria virtual, es decir, la capacidad de trabajar con
procesos mayores que el de la memoria central. Estos esquemas son bastante
complejos y requieren del apoyo de hardware especializado.
Manejo de entradas y salidas
El
sistema de entrada/salida se divide en dos sistemas complementarios: el
estructurado por bloques y el estructurado por caracteres. El primero se usa
para manejar cintas y discos magnéticos, y emplea bloques de tamaño fijo (512
o 1024 bytes) para leer o escribir. El segundo se utiliza para atender a las
terminales, líneas de comunicación e impresoras, y funciona byte por byte.
En
general, el sistema Unix emplea programas especiales (escritos en C) conocidos
como manejadores (drivers) para atender a cada familia de dispositivos de E/S.
Los procesos se comunican con los dispositivos mediante llamadas a su manejador.
Además, desde el punto de vista de los procesos, los manejadores aparecen como
si fueran archivos en los que se lee o escribe; con esto se logra gran
homogeneidad y elegancia en el diseño.
Cada
dispositivo se estructura internamente mediante descriptores llamados número
mayor, número menor y clase (de bloque o de caracteres). Para cada clase hay un
conjunto de entradas, en una tabla, que aporta a los manejadores de los
dispositivos. El número mayor se usa para asignar manejador, correspondiente a
una familia de dispositivos; el menor pasa al manejador como un argumento, y éste
lo emplea para tener acceso a uno de varios dispositivos físicos semejantes.
Las
rutinas que el sistema emplea para ejecutar operaciones de E/S están diseñadas
para eliminar las diferencias entre los dispositivos y los tipos de acceso. No
existe distinción entre acceso aleatorio y secuencial, ni hay un tamaño de
registro lógico impuesto por el sistema. El tamaño de un archivo ordinario está
determinado por el número de bytes escritos en él; no es necesario
predeterminar el tamaño de un archivo.
El
sistema mantiene una lista de áreas de almacenamiento temporal (buffers),
asignadas a los dispositivos de bloques. El Kernel usa estos buffers con el
objeto de reducir el tráfico de E/S. Cuando un programa solicita una
transferencia, se busca primero en los buffers internos para ver si el bloque
que se requiere ya se encuentra en la memoria principal (como resultado de una
operación de lectura anterior). Si es así, entonces no será necesario
realizar la operación física de entrada o salida.
Existe
todo un mecanismo de manipulación interna de buffers (y otro de manejo de
listas de bytes), necesario para controlar el flujo de datos entre los
dispositivos de bloques (y de caracteres) y los programas que los requieren.
Por
último, y debido a que los manejadores de los dispositivos son programas
escritos en lenguaje C, es relativamente fácil reconfigurar el sistema para
ampliar o eliminar dispositivos de E/S en la computadora, así como para incluir
tipos nuevos.
Lenguaje de control del sistema operativo
Entre
los rasgos distintivos de Unix está el lenguaje de control que emplea, llamado
Shell. Es importante analizar dos funciones más de Shell, llamadas
redireccionamiento e Interconexión.
Asociado
con cada proceso hay un conjunto de descriptores de archivo numerados 0, I y 2,
que se utilizan para todas las transacciones entre los procesos y el sistema
operativo. El descriptor de archivo 0 se conoce como la entrada estándar; el
descriptor de archivo 1, como la salida estándar, y el descriptor 2, como el
error estándar. En general, todos están asociados con la terminal de vídeo,
pero, debido a que inicialmente son establecidos por Shell, es posible
reasignarlos.
Una
parte de la orden que comience con el símbolo ? se considera como el nombre del
archivo que será abierto por Shell y que se asociará con la entrada estándar;
en su ausencia, la entrada estándar se asigna a la terminal. En forma similar,
un archivo cuyo nombre está precedido por el símbolo > recibe la salida estándar
de las operaciones.
Cuando
Shell interpreta la orden
califica
< examen > resulta
llama
a ejecución al programa califica (que ya debe estar compilado y listo para
ejecutar) y detecta la existencia de un archivo que toma el lugar de la entrada
estándar y de otro que reemplaza a la salida estándar. Después, pasa como
datos de lectura los contenidos del archivo examen recién abierto (que debe
existir previamente) al programa ejecutable. Conforme el programa produce datos
como salida, éstos se guardan en el archivo resulta que Shell crea en ese
momento.
En
la teoría de lenguajes formales desempeñan un importante papel las gramáticas
llamadas de tipo 3 (también conocidas como regulares), que tienen múltiples
aplicaciones en el manejo de lenguajes. Existen unas construcciones gramaticales
conocidas como expresiones regulares, con las que se puede hacer referencia a un
conjunto ilimitado de nombres con estructura lexicográfica similar; esto lo
aprovecha Shell para dar al usuario facilidades expresivas adicionales en el
manejo de los nombres de los archivos. Así, por ejemplo, el nombre carta * se
refiere a todos los archivos que comiencen con el prefijo carta* y que sean
seguidos por cualquier subcadena, incluyendo la cadena vacía; por ello, si se
incluye el nombre carta* en alguna orden, Shell la aplicará a los archivos
carta, carta1, carta2 y cualquier otro que cumpla con esa especificación
abreviada. En general, en lugares donde se emplea un nombre o una trayectoria,
Shell permite utilizar una expresión regular que sirve como abreviatura para
toda una familia de ellos, y automáticamente repite el pedido de atención para
los componentes. Existen además otros caracteres especiales que Shell reconoce
y emplea para el manejo de expresiones regulares, lo que proporciona al lenguaje
de control de Unix mayor potencia y capacidad expresiva.
En
Unix existe también la posibilidad de ejecutar programas sin tener que
atenderlos en forma interactiva, sino simulando paralelismo (es decir, atender
de manera concurrente varios procesos de un mismo usuario). Esto se logra
agregando el símbolo & al final de la línea en la que se escribe la orden
de ejecución. Como resultado, Shell no espera que el proceso "hijo''
termine de ejecutar (como haría normalmente), sino que regresa a atender al
usuario inmediatamente después de haber creado el proceso asincrónico,
simulando en esta forma el procesamiento por lotes ( batch ) Para cada uno de
estos procesos Shell proporciona, además, el número de identificación, por lo
que si fuera necesario el usuario podría cancelarlo posteriormente, o averiguar
el avance de la ejecución.
La
comunicación interna entre procesos (es decir, el envío de mensajes con los
que los diversos procesos se sincronizan y coordinan) ocurre mediante el
mecanismo de interconexiones (pipes) ya mencionado, que conecta la salida estándar
de un programa a la entrada estándar de otro, como si fuera un conducto con dos
extremos, cada uno de los cuales está conectado a su vez a un proceso distinto.
Desde Shell puede emplearse este mecanismo con el símbolo | en la línea donde
se escribe la orden de ejecución.
Así
en el ejemplo:
(califica
< tarea | sorte > lista) &
se
emplean las características de interconexión, redireccionamiento y asincronía
de procesos para lograr resultados difíciles de obtener en otros sistemas
operativos. Aquí se pide que, en forma asincrónica (es decir, dejando que la
terminal siga disponible para atender otras tareas del mismo usuario), se
ejecute el programa califica para que lea los datos que requiere del archivo
tareas; al terminar, se conectará con el proceso sort (es decir, pasará los
resultados intermedios) para que continúe el procesamiento y se arreglen los
resultados en orden alfabético; al final de todo esto, los resultados quedarán
en el archivo lista.
Con
esta otra orden, por ejemplo, se busca obtener todos los renglones que contengan
las palabras "contrato" o "empleado" en los archivos en
disco cuyos nombres comiencen con la letra "E" (lo cual se denota
mediante una expresión regular). Para lograrlo, se hace uso de una función
llamada egrep, especial para el manejo de patrones y combinaciones de
expresiones regulares dentro de los archivos:
egrep-n
'contrato' 'empleado' E *
Los
resultados aparecen así:
Emple1:
5: en caso de que un empleado decide hacer uso de la facilidad,
Emple1:7:
y el contrato así lo considere las obligaciones de la
Emple2:9:
Cláusula II: El contrato colectivo de trabajo
Emple2:15:
Fracción llI: El empleado tendrá derecho, de acuerdo con lo
El
tercer renglón, por ejemplo, muestra el noveno renglón del archivo Emple2, que
contiene una de las palabras buscadas.
Como
Unix fue diseñado para servir de entorno en las labores de diseño y producción
de programas, ofrece - además de su filosofía misma - un rico conjunto de
herramientas para la creación de sistemas complejos, entre las que destaca el
subsistema make. Este último ofrece una especie de lenguaje muy sencillo, con
el cual el programador describe las relaciones estructurales entre los módulos
que configuran un sistema completo, para que de ahí en adelante make se
encargue de mantener el sistema siempre al día. Es decir, si se modifica algún
módulo, se reemplaza o se añade otro, las compilaciones individuales, así
como las cargas y ligas a que haya lugar, serán realizadas en forma automática,
por esta herramienta. Con una sola orden, entonces, es posible efectuar decenas
de compilaciones y ligas predefinidas entre módulos, y asegurarse de que en
todo momento se tiene la última versión de un sistema, ya que también se
lleva cuenta automática de las fechas de creación, modificación y compilación
de los diversos módulos. De esta manera, se convierte en una herramienta casi
indispensable al desarrollar aplicaciones que requieren decenas de programas que
interactúan entre sí o que mantienen relaciones jerárquicas.
Otras
herramientas interesantes son ar, diseñado para crear y mantener bibliotecas de
programas (que serán luego utilizadas por otros programas para efectuar las
funciones ya definidas sin tener que duplicar el código); awk, un lenguaje para
reconocimiento de patrones y expresiones regulares (es decir, generadas por una
gramática regular o de tipo 3), útil para extraer información de archivos en
forma selectiva; lex, un generador de analizadores lexicográfico, y yacc, un
compilador de compiladores. Estos dos últimos se emplean como herramientas en
la creación de compiladores y procesadores de lenguajes.
La
lista complete de funciones, órdenes de subsistemas que forman parte de las
utilerías del sistema operativo Unix es realmente grande, e incluye más de un
centenar, que se pueden agrupar en los siguientes rubros:
Compiladores
de compiladores.
Ejecución
de programas.
Facilidades
de comunicaciones.
Funciones
para control de status.
Funciones
para control de usuarios.
Funciones
para impresión.
Herramientas
de desarrollo de programación.
Lenguaje
C, funciones y bibliotecas asociados.
Macroprocesamiento.
Manejo
de directorios y archivos.
Manejo
de gráficas.
Manejo
de información.
Manejo
de terminales.
Mantenimiento
y respaldos.
Otros
lenguajes algorítmicos integrados.
Preparación
de documentos.