Procesos y programación del intérprete de órdenes

Contenidos

Introducción

Un proceso es un programa en ejecución, cargado en memoria (bien en memoria principal o en el área de swap). La mayoría de las plataformas disponen de un único procesador por lo que realmente en cada instante sólo un proceso se encuentra en ejecución; por otra parte los usuarios no preparan sus programas para que sus procesos cedan el uso del procesador a otros, por lo que un proceso en ejecución no cedería la CPU hasta que finalizara. Para resolver esta situación el sistema operativo UNIX considera el procesador como otro recurso del sistema (al igual que el disco, la memoria, etc.) y se encarga de distribuirlo entre los diferentes procesos. La parte del núcleo del sistema operativo que gestiona el acceso al procesador se denomina gestor o planificador de procesos (o scheduler) y se encarga de repartir el uso del procesador durante pequeños instantes de tiempo (denominados quanta o rodajas de tiempo) entre los diferentes procesos activos.
 

Estados de un proceso

Como en cada instante sólo un proceso puede estar en ejecución se definen diferentes estados:

Modelo de los procesos en UNIX

En UNIX todo proceso consta de tres áreas de memoria o segmentos:
  • Segmento de Instrucciones (Instruction o Text Segment): contiene el conjunto de instrucciones del programa a ejecutar por el procesador y no es posible alterarlo.

  •  
  • Segmento de Datos de Usuario (User Data Segment): en este área es donde se sitúan las variables definidas por el usuario dentro del programa.

  •  
  • Segmento de Datos del Sistema (System Data Segment): es el área de memoria asociada al proceso y gestionada por el kernel que contiene información de caracterización y control. No es directamente accesible aunque se puede alterar parcialmente a través de llamadas al sistema. El conjunto de información que caracteriza un proceso se conoce con el nombre de entorno del proceso.
  • Por tanto, un programa es una colección de instrucciones y datos almacenados en un archivo que se usa para iniciar los segmentos de instrucciones y datos de usuario, no existiendo ninguna conexión entre el programa y el proceso después.
    Es posible tener múltiples procesos que ejecuten a la vez el mismo programa. En estos casos es una técnica habitual que la parte de código sea compartida por todos los procesos y que la parte de datos sea individual a cada una de ellos.
    En UNIX todo proceso es creado por el núcleo (o kernel) del sistema operativo previa petición de otro proceso, estableciéndose una relación jerárquica entre el proceso que realiza la petición de creación (conocido como proceso padre o "creador") y el nuevo proceso (denominado proceso hijo). Un proceso padre puede tener varios hijos y todo hijo tiene únicamente un padre.
    Esta relación jerárquica en forma de árbol se representa gráficamente como se muestra a continuación:
    Es posible definir prioridades entre los procesos de manera que los más prioritarios tengan preferencia en el uso de la CPU. Cuando un proceso termina (muere), el sistema lo destruye recuperando sus recursos para que puedan ser usados por otros.
    A cada proceso se le asigna un número único en el sistema conocido como PID (Process IDentificator) que lo identifica y distingue de los demás. El PID no varía durante el tiempo de vida del proceso. El PPID de un proceso es el PID de su proceso padre. Un proceso inicial de arranque del sistema da origen a la jerarquía de procesos; su nombre es init y su PID es 1.

    Shell y el modelo de los procesos

    La shell emplea el modelo de procesos del sistema UNIX para realizar su trabajo.
    Después de que el proceso login identifique al usuario como válido, realiza una llamada al sistema para reinicializar sus segmentos de datos y de instrucciones por los de la shell especificada para ese usuario en el archivo /etc/password. La shell resultante se denomina shell de login y se distingue de las shell ordinarias (creadas por clonación u otros mecanismos) por que comienza ejecutando las ordenes existentes en el archivo /etc/profile y en el .profile dependiente del directorio de conexión del usuario.
    En el primero de estos archivos el administrador del sistema sitúa una serie de órdenes de configuración comunes a todos los usuarios mientras que el segundo es empleado por cada usuario para personalizar su sesión según sus preferencias.
    Entre los recursos asociados a un proceso se encuentra la interfaz estándar de comunicación con el exterior. Esta interfaz consta de tres elementos conocidos como archivos de entrada, salida y errores estándar.
    En UNIX, cuando un proceso abre un archivo, el kernel le entrega un número entero positivo, conocido como descriptor de archivo, que el proceso utilizará para realizar operaciones posteriores de E/S. Los descriptores asociados a los archivos estándar son:
    Descriptor Denominación
    0 stdin (entrada estándar) por defecto está asociada con el teclado del terminal. 
    1 stdout (salida estándar) asociada con la pantalla del terminal
    2 stderr (salida de errores estándar) asociada con la pantalla del terminal. Se usa para sacar mensajes importantes cuando se producen situaciones anómalas.
    Los descriptores estándar de entrada, salida y error pueden ser redirigidos para conseguir que la información se envíe o se tome de un archivo en lugar del terminal del usuario.
    Ejemplo: La siguiente orden enviará el contenido del archivo saludo.txt al usuario so99: la orden mail tomará la información necesaria para su funcionamiento (el texto del mensaje) del archivo saludo.txt en lugar del terminal.
    $ mail so99 < saludo.txt
    Ejemplo: En este caso la salida de la orden banner no será enviada al terminal sino que será almacenada en el archivo saludo.txt.
    $ banner hola > saludo.txt
    Ejemplo: La información que la orden time envíe por la salida de errores estándar será almacenada en el archivo tiempo.txt en lugar de mostrarse en pantalla. El uso de paréntesis es necesario en este caso para evitar que sea la salida de errores de la orden date la que se redirija.
    $ (time date) 2> tiempo.txt
    Los operadores de redirección son evaluados de izquierda a derecha, siendo el orden de las redirecciones importante.
    Cuando se ejecuta un programa, éste no le devuelve el control al usuario hasta que no termina su ejecución. Esta forma de trabajo imposibilita que un usuario pueda ejecutar varios programas simultáneamente.
    Ejemplo:
    $ sleep 60
    La línea anterior hace que el terminal duerma durante 60 segundos.
    Un forma de ejecutar programas y recobrar el control del terminal inmediatamente, es la ejecución en background, modo sumergido o asíncrona.
    La forma de ejecutar un programa u orden en background es:
    $ nombre_programa &
    Ejemplo:

    $ sleep 60 &
    [1] 644
    $ ps
    USER PID PPID %CPU STARTED TT TIME COMMAND
    ssp 613 612 0.0 16:57:26 p1 0:00.29 - (ksh)
    ssp 644 613 0.0 17:05:29 p1 0:00.02 sleep 60

    Como se observa en los ejemplos anteriores, al ejecutar una orden en modo sumergido, la shell muestra un número entre corchetes conocido como identificador de trabajo y el PID del proceso de más alta jerarquía de los que se ponen en marcha de manera asíncrona.
    Mediante el operador ; es posible construir listas de órdenes que serán ejecutadas en secuencia por la shell.
    Las palabras reservadas { } han de ir separadas de las órdenes por espacios en blanco; además es necesario situar un carácter de separación de orden (; o salto de línea) delante del símbolo }.
    Los operadores ( ) también se pueden emplear para agrupar ordenes; no aplicándoseles las reglas anteriores.
    Ejemplo:
    $ (echo Directorio:;pwd)
    Directorio:
    /users/chan

    Variables de entorno y variables shell

    El entorno de un proceso es el conjunto de variables que definen y caracterizan las condiciones bajo las que se ejecuta. En UNIX se distinguen dos tipos de variables: variables shell y variables de entorno.
    Caracterizan a la shell , y a diferencia de las variables de entorno, no se transmiten a los procesos hijo. Para definir una variable shell basta con teclear:
    [set] identificador=valor
    Ejemplo:
    $ DIA=Viernes
    No deben teclearse espacios en blanco en torno al operador de asignación (=). Se puede obtener un listado de todas las variables (shell y entorno) tecleando set sin argumentos.
    Una variable shell puede transformarse en una variable de entorno mediante la orden interna export.
    Caracterizan el entorno de trabajo de la shell y los hijos que genere (puesto que se transmiten -heredan- de padres a hijos). Sus valores se fijan en los archivos:
    /etc/profile: aquí se definen las variables de entorno comunes a todos los usuarios.

    .profile: si en el directorio de conexión del usuario existe este archivo, ksh lo ejecuta; mediante este mecanismo cada usuario puede personalizar su entorno.

    ENV: variable de entorno que contiene el nombre del último archivo de configuración que se ejecutará. Suministra un mecanismo adicional para que los usuarios personalicen su entorno. Habitualmente no se suele fijar o si se fija se hace al archivo .kshrc del directorio de conexión del usuario.

    export

    Sintaxis: export [identificador[=valor]]...
    Define, marca (y/o asigna) el identificador (o identificadores) como variables de entorno que serán exportadas a los procesos hijo que se generen. export sin argumentos muestra una lista con los pares variable de entorno , valor en ese momento.
    Ejemplo:
    $ export TERM=vt100 fija y exporta la variable TERM
    Variable Descripción
    HOME contiene el camino absoluto del directorio de conexión del usuario.
    PWD contiene el camino absoluto del directorio de trabajo
    PATH contiene el conjunto de caminos empleados para buscar las ordenes a ejecutar. Se pueden especificar múltiples caminos separándolos mediante :.
    PS1 el valor de esta variable se utiliza como inductor de órdenes primario (prompt) de la ksh. Dentro de esta cadena, el carácter ! es reemplazado por el número de comando. Por defecto su valor es $.
    SHELL contiene el camino absoluto de la shell.
    ? valor decimal retornado por la última orden ejecutada.
    Anteponiendo el operador de sustitución ($) inmediatamente delante del nombre de la variable, ésta será sustituida por su valor.
    Ejemplo:
    $ echo Valor de la variable HOME: $HOME
    Valor de la variable HOME: /users/atc/chan

    unset

    Sintaxis: unset identificador ...
    Mediante esta orden, tanto las variables de entorno como las shell pueden ser eliminadas.
    Ejemplo:
    $ echo Mi tipo de terminal es $TERM
    Mi tipo de terminal es vt100
    $ unset TERM
    $echo Mi tipo de terminal es $TERM
    ksh: TERM: parameter not set
    $

    Mecanismos de comunicación entre procesos

    Aunque en UNIX existe un amplio conjunto de herramientas que permiten intercambiar información entre procesos, a través de la Bourne shell sólo se suministra un conjunto reducido de éstas: tuberías, señales y valores de retorno.
    Las tuberías o pipelines son una herramienta de comunicación entre procesos que permiten conectar la salida estándar de un proceso con la entrada estándar de otro. Así todo lo que el proceso (productor) envíe a su salida estándar será tomado por el otro proceso (consumidor) como entrada en el mismo orden en que se generó la información.
    La forma de indicar que se quiere emplear una tubería para comunicar dos o más procesos es la siguiente:
    $ productor | consumidor

    $ orden_1 | orden_2 |orden_3 | ...

    Ejemplo:
    $ banner "hola" | write so25
    La salida de la orden banner es utilizada para enviar un mensaje al usuario so25
    $
    Una señal es un interrupción software que le avisa al proceso de que se ha producido algún evento. Un proceso puede recibir señales durante su tiempo de ejecución. Las señales son enviadas por el kernel a los procesos aunque pueden ser generadas por otros procesos, por los usuarios o por el propio kernel. Algunas señales pueden ser interpretadas también como órdenes que recibe el proceso. La orden para enviarle una señal a un proceso es kill:

    kill

    Sintaxis: kill [-número_señal] PID
    Si no se especifica ningún número de señal, kill envía la número 15.
    Algunos números de señal importantes son:
    2 Interrupción. Se genera al pulsar Ctrl+c

    9 Terminación abrupta del proceso

    15 Terminación controlada del proceso

    Todo proceso que finaliza devuelve un número entero entre 0 y 255 que representa la causa por la que terminó:
    0: terminación correcta del proceso. Representa un valor lógico verdadero cuando se usa dentro de una comparación o iteración. Cualquier otro valor distinto de 0 se considera como falso.

    1: indica terminación anormal del proceso (fallo).

    129 ... 160: El proceso terminó como consecuencia de una señal. Restando 128 al valor de retorno se obtiene el código de la señal que terminó el proceso.

    La variable de entorno ? mantiene el valor de retorno de la última orden ejecutada.
    Ejemplo:
    $ date 02251295
    date: bad conversion
    $echo El valor de retorno de la última orden fue: $?
    El valor de retorno de la última orden fue: 2
    $

    Algunas órdenes relacionadas con los procesos

    Sintaxis: ps [parámetros]
    El monitor de procesos es un programa que se comunica con el sistema operativo para interrogarlo sobre los procesos que está gestionando.
    Ejemplo:
    $ ps -f
    USER PID PPID %CPU STARTED TT TIME COMMAND
    ssp 613 612 0.0 16:57:26 p1 0:00.25 - (ksh)
    ssp 639 613 0.0 17:03:52 p1 0:00.03 sh
    El significado de las distintas columnas es el siguiente:
    USER    Nombre del usuario que está ejecutando el proceso
    PID     Identificador del proceso
    PPID    Identificador del proceso padre.
    %CPU    Tiempo de CPU que lleva consumido el proceso.
    STARTED Hora de inicio del proceso
    TT      Terminal de control asociado al proceso.
    TIME    Tiempo total asociado al proceso.
    COMMAND Orden que se ejecutó para iniciar el proceso.
    Sintaxis: time orden [argumentos]
    time ejecuta la orden especificada y muestra por la salida de errores estándar:
    1. tiempo transcurrido en el sistema mientras se ejecutaba la orden.
    2. tiempo consumido en la ejecución de la orden.
    3. tiempo empleado por el sistema para la ejecución de la orden (llamadas al sistema, ...).
    Ejemplo:
    $ time who
    chan pty/ttys0 Oct 24 16:33
    real 0m0.42s
    user 0m0.07s
    sys 0m0.07s
  • sleep
  • Sintaxis: sleep segundos
    Suspende la ejecución durante los segundos especificados como parámetro. Se usa para ejecutar una orden después de un cierto tiempo.
    Ejemplo:
    $ sleep 20; echo Han pasado 20 segundos
    Han pasado 20 segundos

    Programas shell (shell scripts)

    La  bash-shell es un potente intérprete de órdenes que dispone de un amplio conjunto de herramientas para caracterizar su comportamiento y el entorno en que esas órdenes se ejecutan; pero también puede ser considerada como un lenguaje de programación de características avanzadas, que dispone de todas las estructuras de control existentes en lenguajes modernos como C, Pascal, Modula, etc.

    Un shell script o programa shell es un archivo que contiene un conjunto de órdenes que pueden ser interpretadas y ejecutadas por la shell. Para que la shell pueda ejecutarlo hay que activar los permisos de ejecución adecuados. La edición de estos programas shell puede realizarse con cualquier editor de textos ASCII como vi.

    Cualquier línea que comience por el carácter # es considerada por la shell como un comentario. Es recomendable incluir comentarios en los programas shell para mejorar su legibilidad.

    Ejemplo:

    $ cat cwdir
    # Este programa shell muestra el directorio de trabajo y
    # los archivos que contiene en formato largo:
    echo Directorio de trabajo: $(pwd)
    echo Contenido:
    ls -l

    A continuación, mediante la orden chmod, se dota al archivo de los permisos adecuados para su ejecución:

    $ chmod +x cwdir

    el shell script está listo para su ejecución:
    Los programas shell pueden recibir argumentos por la línea de órdenes. Estos parámetros posicionales están asociados a los nombres de variable siguientes:
    $0: identifica al parámetro 0 o nombre del programa.

    $1: identifica al primer argumento pasado al programa por la línea de órdenes

    ...

    $9: identifica al noveno argumento de la línea de órdenes.

    Aunque una línea de órdenes puede tener más de nueve parámetros, un programa shell sólo puede acceder directamente a los primeros nueve parámetros mediante $1...$9; para argumentos superiores se emplea la notación ${número_argumento}.
    Las siguientes variables, se encuentran relacionadas con los parámetros posicionales:
    $#: contiene el número de parámetros posicionales sin incluir el cero.

    $*: cadena de argumentos recibidos por el script sin incluir el cero.

    Ejemplo:
    $ cat parametros
    echo Este script se ejecuta tecleando $0 y una secuencia de parametros.
    echo En este caso se han suministrado $# parametros
    echo La cadena de parametros es: $*
    echo 1er parametro: $1
    echo 2º parametro: $2
    Se graba el archivo (:wq) y se le dota de los permisos necesarios para su ejecución:
    $ chmod +x parametros
    $ parametros aa bb cc dd ee ff
    Este script se ejecuta tecleando parametros y una secuencia de parametros. En este caso se han suministrado 6 parámetros
    La cadena de parametros es: aa bb cc dd ee ff
    1er parametro: aa
    2º parametro: bb
    $

    Mecanismos de escape

    Los mecanismos de escape son aquellos que sirven para evitar que la shell interprete caracteres especiales o palabras reservadas con su significado habitual, tomándolos entonces como literales. Estos mecanismos evitan, por tanto, la expansión de parámetros o la sustitución de órdenes. Los caracteres empleados como mecanismos de escape son la barra invertida (\), las comillas simples (´...´) y las comillas dobles ("...").
    La barra invertida tiene las siguientes interpretaciones dependiendo de la situación en la que se encuentre:
  • Si no aparece encerrado entre comillas (simples o dobles), se elimina y el carácter al que precede es tomado como literal. Si el carácter al que acompaña es el de línea nueva, newline, también se elimina este carácter. Este comportamiento se denomina continuación de línea y permite escribir texto en varias líneas y que la bash-shell las considere como una sola.

  •  
  • Si forma parte de texto encerrado entre comillas simples mantiene su significado literal (no es interpretada).

  •  
  • Cuando se encuentra dentro de un texto encerrado entre comillas dobles mantiene su significado literal, excepto cuando se usa para escapar los caracteres $, ` y ".

  •  
  • Dentro de la notación antigua de sustitución de órdenes (`...`) , permite escapar los caracteres $, ` y \.
  • Ejemplo:
    $ echo \$HOME es $HOME \?
    $HOME es \users\so\tracy ?
  • Comillas simples
  • Los caracteres situados dentro de las comillas simples pierden su significado y son tomados como literales.  La comilla simple no puede aparecer dentro del literal puesto que delimitaría el final de la cadena. Fuera de un literal es necesario emplear la secuencia \´ o "´" para referirse al carácter ´.
    Ejemplo:
    $ echo ´$HOME, ", \n, `ls`´
    $HOME, ", \n, `ls`
    $ echo A esto se le denomina "´"escapar\´ el caracter "´"
    A esto se le denomina ´escapar´ el caracter ´
    Eliminan la interpretación de todos los caracteres que encierran excepto $, `, " y \.
    Ejemplo:
    $ echo "\$HOME es $HOME \?"
    $HOME es \users\so\tracy \?

    Sustitución de órdenes

    Esta técnica consiste en sustituir el nombre de una orden por su salida estándar. Para realizar esta transformación, la orden ha de introducirse entre los caracteres especiales `...` (tildes graves). Esta notación se conoce también como antigua sustitución de órdenes, puesto que es la empleada por la Bourne shell y C-shell. Empleando esta notación se eliminan los caracteres de escape (\) que preceden a los caracteres especiales $, ´ y \ antes de ejecutar la orden. Esto permite incluir estos caracteres evitando que sean interpretados por la shell.

    Ejemplo:

    $ echo El directorio actual o de trabajo es: `pwd`
    El directorio actual o de trabajo es: \users\so\atc\chan
    $
    La bash-shell define además una nueva sustitución de órdenes a través de $(...) con la misma semántica asociada. Este interprete sigue siendo compatible con la notación antigua. La nueva notación suministra una sintaxis más sencilla, puesto que todos los elementos incluidos dentro de $(...) formarán parte de la orden; estando permitido además su anidamiento. Además, la expresión $(< archivo)expande el contenido de un archivo. La única regla a tener en cuenta ahora se refiere al uso de paréntesis no emparejados dentro de $(...), en este caso se hace necesario introducirlos dentro de comillas simples.

    Ejemplo:

    $ archivoS_TEXTO=$(ls *.txt)
    $ head -2 $archivoS_TEXTO
    ==> informe.txt <==

    Almería 30 de Marzo de 2000

    ==> pracsept.txt <==

    Hola

    $

    Filtros. Algunos filtros básicos

    Cualquier proceso que lea de su entrada estándar y escriba en su salida estándar se denomina filtro. Un ejemplo de lo anterior es cat; sin argumentos, esta orden toma la información del teclado y cuando finaliza su entrada, escribe su salida en pantalla. En UNIX la marca de fin de archivo se representa con el carácter Ctrl+d (^d).

    En general, los filtros permiten realizan tareas más sofisticadas sobre la entrada estándar como ordenación de la entrada; selección , búsqueda y sustitución de patrones, etc. pudiendo alcanzarse un grado considerable de complejidad cuando se concatenan entre sí. A continuación se estudian algunos de los filtros más básicos como son wc, sort, cut, y grep.

    wc

    Sintaxis: wc [-lwc][archivo1 ...]
    wc cuenta el número de caracteres, palabras y líneas por cada archivo que recibe como parámetro y el total de cada una de las categorías para todos los archivos. Si no se especifica ningún parámetro, wc realiza estas operaciones sobre el archivo de entrada estándar. Las opciones posibles limitan el tipo de información generada:
    -c cuenta únicamente el número de caracteres.

    -l sólo el número de líneas.

    -w sólo el número de palabras.

    Ejemplo:
    $ wc
    Esta linea tiene cinco palabras
    esta solo tres
    (Se pulsa ^d para indicar fin de entrada estándar)
    2 8 47
    (wc indica que el texto recibido constaba de 2 líneas 8 palabras y 47 caracteres)
     

    $ echo Tres tristes tigres ... > xxx
    $ echo comian trigo en un trigal > yyy
    $ wc -w xxx yyy
    4 xxx
    5 yyy
    9 total
    $

    sort

    Sintaxis: sort [-dfnrb] [-t carácter] [+pos1 [-pos2]] [archivo1 ...]
    sort ordena las líneas de los archivos archivo1 ... y las envía a la salida estándar. Si no se especifica ningún archivo o una de los archivos es -, entonces toma las líneas de la entrada estándar. Para la ordenación se emplean uno o varios campos claves extraídos de cada línea. Por defecto el campo empleado como clave es la línea completa.
    Las opciones de este filtro se pueden dividir en varias categorías:
    Estas opciones permiten modificar el criterio de ordenación; las más comunes son:
    -d sólo las letras, dígitos y caracteres en blanco son significativos en la ordenación.

    -f ordena sin distinguir las mayúsculas de las minúsculas.

    -n interpreta los valores de las líneas a ordenar como numéricos y los ordena según ese criterio.

    Ejemplo:
    Sin opción Con opción
    $ sort
    !increible¡
    aburrido
    (Ctrl+d)
    !increible¡
    aburrido
    $
    $ sort -d
    !increible¡
    aburrido
    (Ctrl+d)
    aburrido
    !increible¡
    $
    $ sort
    anterior
    POSTERIOR
    (Ctrl+d)
    POSTERIOR
    anterior
    $
    $ sort -f
    anterior
    POSTERIOR
    (Ctrl+d)
    anterior
    POSTERIOR
    $
    $ sort
    90
    20
    100
    (Ctrl+d)
    100
    20
    90
    $
    $ sort -n
    90
    20
    100
    (Ctrl+d)
    20
    90
    100
    $
    La notación +pos1 -pos2 permite especificar que partes o campos de una línea se utilizaran como claves de ordenación. pos1 y pos2 representan respectivamente los valores numéricos del rango de campos que se tomarán como claves para realizar la ordenación. Si no se especifica -pos2, entonces se ordena tomando como clave desde el campo pos1 hasta el fin de la línea.
    Al especificar los campos empleados como claves de ordenación es importante tener en cuenta que un valor n hace referencia al campo n+1 de la línea, por lo que el primer campo de la línea se referencia como 0, el segundo como 1 y así sucesivamente.
    sort considera un campo como una cadena de caracteres seguida por un delimitador. Por defecto los delimitadores son caracteres en blanco, tabuladores o caracteres de fin de línea, con lo que un campo es cualquier palabra de un texto. Dos caracteres delimitadores sucesivos se definen un campo vacío. Es posible modificar este comportamiento a través de las siguientes opciones:
    -t carácter se emplea carácter como separador de campos.

    -b ignora los espacios en blanco y tabuladores no significativos dentro de las claves de ordenación.

    Ejemplo:
    Sin opción Con opción
    $ cat xxx
    las palabras sin sentido
    son palabras sin latido
    sin palabras, tan perdidos ...
    $ sort xxx
    las palabras sin sentido
    sin palabras, tan perdidos ...
    son palabras sin latido
    $
    $ sort +1 xxx
    son palabras sin latido
    las palabras sin sentido
    sin palabras, tan perdidos ...
    $ sort +1 -2 xxx
    las palabras sin sentido
    son palabras sin latido
    sin palabras, tan perdidos ...
    $
    $ sort
    antes
    despues
    (Ctrl+d)
    despues
    antes
    $
    $ sort -b
    antes
    despues
    (Ctrl+d)
    antes
    despues
    $

    cut

    Sintaxis: cut -c lista [archivo1 ...]
       cut -f lista [-d carácter] [-s] [archivo1 ...]
    cut extrae uno o varios campos para cada línea de un archivo. Los campos a extraer se especifican en lista y pueden ser de longitud variable o fija. En el primer caso es necesario especificar un carácter delimitador de campo. Si no se especifican archivo1 ... se utiliza la entrada estándar. El significado de las opciones es el siguiente:
    lista es una lista de números enteros que se emplean para especificar los campos a extraer. Los elementos de la lista deben separarse por comas y ordenarse en orden creciente. Se pueden especificar rangos empleando -. Ejemplo:
    1, 3, 7 selecciona los campos 1º, 3º y 7º.

    1-5, 8 selecciona los cinco primeros campos y el 8º. Este rango se puede especificar también como -5,8.

    2-5, 8 selecciona los campos 2º a 5º (ambos incluidos) y todos los campos desde el 8º al último.

    -c las especificaciones de campos que aparecen en la lista se refieren a las posiciones que ocupan los caracteres dentro de la línea. Cada carácter es un campo.

    -f los campos se encuentran separados por delimitadores por lo que un campo puede contener varios caracteres. El carácter delimitador puede ser especificado por la opción -d. Las líneas sin caracteres delimitadores se transcriben intactas a la salida estándar salvo que se especifique la opción -s.

    -d carácter permite especificar el carácter delimitador de campo. Si no se especifica esta opción, se toma como delimitador por defecto el carácter de tabulación. Para especificar el espacio en blanco o caracteres especiales de la shell, es necesario encerrarlos entre comillas. Dos caracteres delimitadores consecutivos delimitan un campo vacío.
    -s con esta opción se eliminan de la salida estándar las líneas que no contengan caracteres delimitadores.
    Ejemplo:
    $ who | cut -c 1-9
    chan
    tracy
    root
    $ cat agenda
    Dick Tracy:tracy@pareatis.lightwind.es
    Sharleen Spiteri:sharleen@texas.com
    archie:archie@quiche.cs.mcgill.ca
    $ cut -f 2 -d':' agenda
    tracy@pareatis.lightwind.es
    sharleen@texas.com
    archie@quiche.cs.mcgill.ca
    $

    grep

    Sintaxis: grep [-ilnsv] patron1 [archivo1 ...]
           grep [-ilnsv] [-f archivo_patrones] [archivo1...]
           grep [-ilnsv] -e patron1 [-e patron2 ...] [archs...]
    grep busca los patrones de texto especificados por patron1, patron2, ... en los archivos archivo1, ... Normalmente cada línea emparejada se envía a la salida estándar, precedida por el nombre del archivo en que se encontró, si se especificaron varios. Si no se especifica ningún archivo busca los patrones en la entrada estándar. grep dispone de una amplia gama de opciones; a continuación se detallan las más habituales:
    -f archivo_patrones esta opción permite especificar un nombre de archivo del que se tomaran los patrones a emparejar. Los patrones que se deseen buscar han de escribirse cada uno en una línea dentro del archivo_patrones. Una línea de un archivo se envía a la salida estándar si se empareja con cualquiera de los patrones.

    -e patrón mediante esta opción se permite especificar múltiples patrones en la línea de órdenes.

    -i trata mayúsculas y minúsculas sin distinción durante la comparación; así, el patrón la se emparejaría con las cadenas la, La, lA o LA.

    -l limita la salida de la orden a los nombres de los archivos que contienen líneas emparejadas con algún patrón.

    -n cada línea emparejada aparece precedida por su posición dentro del archivo. Esta opción se ignora si está activa la anterior.
    -s no se muestra ningún tipo de error que pudiera producirse.

    -v se muestran sólo las líneas que no se emparejan.

    Los patrones pueden contener caracteres especiales, por lo que para evitar que sean interpretados por la shell conviene introducir los patrones entre comillas.
    Ejemplo:
    $ cat agenda
    Dick Tracy:tracy@pareatis.lightwind.es
    Sharleen Spiteri:sharleen@texas.com
    $ grep -ni spiteri agenda
    2:Sharleen Spiteri:sharleen@texas.com
    $ echo archivo con cuatro palabras > f1.txt
    $ echo un archivo con cinco palabras > f2.txt
    $ grep -l cinco *.txt
    f2.txt
    $

    Ejercicios

    3.1. Explique que ocurre en los siguiente casos:
    3.2. ¿Qué hace la siguiente pipeline?
    who | wc -l
    3.3. Explicar qué hacen y qué diferencias existen entre las siguientes secuencias de ordenes:
     
    CONEXION=$HOME
    echo $CONEXION
    ksh
    echo $CONEXION
    ^d
    echo $CONEXION
    CONEXION=$HOME
    export CONEXION
    echo $CONEXION
    ksh
    echo $CONEXION
    CONEXION=/tmp
    echo $CONEXION
    ^d
    echo $CONEXION

     3.4. Mediante el editor  nedit realice un shell script que cuente el número de archivos que hay en el directorio de conexión. Explique detalladamente todos los pasos

    3.5. Debido a un fallo del administrador del sistema las ordenes vi y cp han sido borradas. ¿Podrá copiar el archivo /etc/passwd en su subdirectorio p3 sin la ayuda de esas órdenes?. Explique su respuesta.

    3.6. Realice un programa shell que reciba como parámetros tres palabras y las muestre en pantalla ordenadas alfabéticamente.

    3.7. El archivo /etc/passwd contiene información administrativa sobre los usuarios del sistema; en particular contiene los nombres de los usuarios dentro del sistema y en la vida real. Desarrollar un programa que muestre en pantalla un listado de los nombres, de usuario y reales, existentes en ese archivo.

    3.8. Desarrolle un shell script que reciba dos parámetros, un directorio y una cadena de caracteres a buscar en todos los archivos regulares que se encuentren en del directorio especificado.

    3.9. Escriba un shell script que de manera perpetua añada cada 5 segundos una línea al archivo usuarios con la siguiente información:

    fecha | nº usuarios conectados en ese instante | lista de los nombres de los usuarios

    Ejemplo:

    Fri Mar 1 17:21:03 EDT 1996 | 3 | root rsis21 imyso12 pepeillo
    Fri Mar 1 17:21:03 EDT 1996 | 4 | rsis21 rges15 imyso12 invitado

    Ejecutar el script en modo sumergido (background)

    3.10. Desarrolle un shell script de nombre matador que reciba como parámetro el nombre de un proceso en ejecución y lo elimine, mostrando además un mensaje como:
    El proceso nombre_proceso con PID PID_proceso_eliminado ha sido eliminado
    Utilice este script para detener el del ejercicio anterior.

    Determine el comportamiento del script en las siguientes situaciones: