Facultad de Ingenierı́a Universidad de Buenos Aires 75.08—Sistemas Operativos UNIX so7508@hotmail.com http://fiuba-7508.50megs.com Apunte por: Ignacio Errico perrico@fi.uba.ar Version Preliminar Marzo de 2003 Índice 1 Introducción. 1.1 1.2 1.3 4 ¿Qué es UNIX? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1.1 ¿Qué es UNIX entonces? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Tareas básicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2.1 Iniciando el sistema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2.2 Iniciar una sesión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2.3 Terminar una sesión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2.4 Cuentas de usuario y claves de usuario. . . . . . . . . . . . . . . . . . . . 6 1.2.5 Terminales virtuales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2.6 El comando su. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.2.7 Apagando el sistema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Conceptos básicos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3.1 Caracteres de control en la lı́nea de comandos. . . . . . . . . . . . . . . . 8 1.3.2 Directorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.3 Permisos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2 El Shell. 2.1 2.2 2.3 2.4 13 Uso de abreviaturas: Metacaracteres. . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.1.1 Nombres de archivos con metacaracteres. . . . . . . . . . . . . . . . . . . 14 Variables de Ambiente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2.1 Obteniendo el valor de variables. . . . . . . . . . . . . . . . . . . . . . . . 15 Variable de usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.3.1 Sustitución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Entrecomillado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2 3 2.4.1 2.5 2.6 Tipos de entrecomillado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Redireccionamiento de la Entrada y Salida. . . . . . . . . . . . . . . . . . . . . . 18 2.5.1 Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Interconexión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3 Programación con el Shell: Shell-Scripting. 21 3.1 Comentarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.2 Argumentos y Parámetros. El comando shift. . . . . . . . . . . . . . . . . . . . 21 3.2.1 Parámetros especiales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2.2 Estado de salida. El comando exit. . . . . . . . . . . . . . . . . . . . . . 23 Pruebas. El comando test. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.3.1 Operadores del comando test. . . . . . . . . . . . . . . . . . . . . . . . . 23 3.3.2 Pruebas sobre archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.3.3 Prueba de valores para operaciones algebraicas. . . . . . . . . . . . . . . . 24 3.3.4 Prueba de valores para cadena de caracteres. . . . . . . . . . . . . . . . . 24 Aritmética entera. El comando expr. . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.4.1 Operador de longitud. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Comandos de control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.5.1 Sentencias de Decisión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.5.2 Sentencias de Iteración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.3 3.4 3.5 4 Comandos de Entrada y Salida. 4.1 4.2 4.3 Traducción de caracteres: el comando tr. . . . . . . . . . . . . . . . . . . . . . . 30 4.1.1 Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 El comando cut. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.2.1 Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 El comando paste. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.3.1 33 Ejemplos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Expresiones Regulares. 5.1 5.2 30 34 Expresiones regulares simples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 5.1.1 Algunos ejemplos de expresiones regulares simples. . . . . . . . . . . . . . 35 Expresiones regulares extendidas. . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5.2.1 36 Ejemplos de REs Extendidas. . . . . . . . . . . . . . . . . . . . . . . . . . Capı́tulo 1 Introducción. 1.1 ¿Qué es UNIX? El sistema operativo UNIX nació como un sistema de tiempo compartido, orientado a usos generales. En 1973, Ritchie y Thompson reescribieron el núcleo del sistema (el kernel ) en C, rompiendo de esta manera la tradición de software de base escrito en assembler. En 1974 se introduce en las universidades con fines educacionales y poco tiempo después estuvo disponible con fines comerciales. UNIX no es en sı́ un sistema operativo, sino un tipo de sistema operativo. Los sistemas operativos tipo UNIX más conocidos son AIX, SCO, SVR4, SOLARIS. El éxito de UNIX se debe principalmente a tres causas: 1. Ventaja comercial. Por estar escrito en C es portable, y se puede ejecutar en una gran variedad de máquinas. 2. Abierto. El código fuente está disponible y escrito en un lenguaje de alto nivel. Esto lo hace fácil de adaptar a exigencias particulares. 3. De utilidad particular para programadores. Es un sistema operativo rico y productivo para programadores. Su eficacia se debe al enfoque de la programación, y no a la programación misma: la combinación de distintos comandos simples permiten lograr grandes tareas generales. De esta manera, monta su potencia en la relación entre los programas, más que en la potencia de los programas propiamente dichos. 1.1.1 ¿Qué es UNIX entonces? En sentido estricto. Es el núcleo de un sistema operativo de tiempo compartido. Un programa que controla los recursos de una computadora y los asigna entre los usuarios. Permite a los 4 Sección 1.2. Tareas básicas. 5 usuarios ejecutar sus programas, controla los dispositivos periféricos conectados, y proporciona un sistema de archivos que permite el almacenamiento a largo plazo de todo tipo de información. En sentido más amplio. Abarca, además del núcleo, programas esenciales como compiladores, editores, lenguajes de comandos, programas para copiar e imprimir archivos, y muchas otras aplicaciones. 1.2 1.2.1 Tareas básicas. Iniciando el sistema. Este proceso puede variar levemente respecto de lo que uno está acostumbrado con otros sistemas operativos. En el caso de no haber instalado otro sistema operativo, el proceso es simplemente encender la computadora y esperar. Por otro lado, si se está compartiendo el sistema con otro sistema operativo, es probable que uno tenga que realizar alguna de las siguientes opraciones: • Seleccionar Linux en el prompt de LILO. Si al instalar el sistema se decidió instalar LILO (LInux LOader ) la computadora está preparada para iniciar el sistema operativo que se le especifique ingresando la etiqueta para la partición definida en la instalación. Presionando la tecla <TAB>, se muestran las etiquetas posibles. Simplemente ingrese la correspondiente a Linux, o presione <ENTER> si es la partición que LILO debe iniciar por defecto. • Iniciar desde un diskette. Si se creó un diskette de booteo al instalar Linux, también se lo puede usar para iniciar el sistema. 1.2.2 Iniciar una sesión. Al iniciar el sistema, o al conectarse a una terminal, se visiualiza el siguiente mensaje: Login: La primera vez que uno entra al sistema, se debe ingresar el usuario root. Este es el nombre del usuario que tiene permiso para todo en el sistema. Por lo general se usa para realizar tareas de administración, como por ejemplo, para crear nuevos usuarios, apagar el sistema, etc. Dado que este usuario tiene permiso para hacer cualquier cosa, hay que saber que comandos se ejecutan al entrar como root. Más adelante hablaremos acerca de permisos. Para ingresar, se debe tipear root y presionar la tecla <ENTER>, y a continuación aparecerá: Password: donde se debe tipear la clave del usuario. Tener presente, que si bien no se visualizan los caracteres cuando uno tipea la clave, se puede corregir con la tecla <BACKSPACE>. Sección 1.2. Tareas básicas. 6 Recuerde que UNIX es un sistema operativo que distingue mayúsculas de minúsculas —es “case sensitive”. Si la clave ingresada es correcta, el sistema mostrará un prompt o sı́mbolo de espera, que a lo largo de este apunte se representará con el sı́mbolo # (para el caso del root), que es normalmente el caracter generado por un programa shell o intérprete de comandos, que es la interfaz entre el sistema operativo y el usuario. 1.2.3 Terminar una sesión. Si bien existen los comandos logout y exit, es común usar CTRL-D. Esto lleva a la pantalla de Login: que se describió antes. 1.2.4 Cuentas de usuario y claves de usuario. Como sugerimos antes, no es una buena idea usar la cuenta de root todo el tiempo. Tarde o temprano uno comete un error, y con este usuario no hay restricciones que salven. Vamos a describir la forma más básica de crear un usuario. En el prompt tipeamos: # useradd igna # passwd igna New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully El comando passwd en general se puede usar para: • Definir claves para nuevos usuarios. • Cambiar claves de usuarios existentes. • Cambiar la clave del usuario loggeado. El comando requiere que la clave se ingrese dos veces para verificar que no hubieron errores de tipeo. 1.2.5 Terminales virtuales. Una herramienta muy útil son las terminales virtuales: se pueden iniciar distintas sesiones simultáneamente, presionando ALT-Fn. Habiendo creado el nuevo usuario igna, uno puede presionar ALT-F2 y loggearse con este nuevo usuario. Para volver a la terminal del root, se presiona ALT-F1. Sección 1.3. Conceptos básicos. 1.2.6 7 El comando su. Hay ocasiones en las cuales uno quiere ejecutar algunos comandos como un usuario distinto del que uno estĺoggeado. Esto es muy útil particularmente para administradores del sistema, que usan sus cuentas sin privilegios por lo general. Para evitar todo el proceso de loggeo se usa el comando su, que hace que la sesión de un usuario ordinario se transforme en una sesión de root. Al ejecutar el comando, pide que se ingrese la clave del root. Este comando resulta muy útil particularmente si uno es su propio administrador de sistema, como sucede con muchos usuarios Linux. 1.2.7 Apagando el sistema. Apagar el sistema no se trata simplemente de apagar la computadora. Aunque uno no esté ejecutando ningún programa, esto no significa que no hay nada corriendo. Lo que hay que hacer es ejecutar el comando shutdown, el cual solo puede ser ejecutado por el root. Esta es una buena oportunidad para usar el comando su. El formato general de shutdown es: shutdown <opciones> <tiempo> El parámetro <opciones> puede ser: • -h: detener el sistema cuando se terminó de cerrar. • -r: reiniciar el sistema. El segundo parámetro, <tiempo>, normalmente es now, aunque también puede ser el valor de minutos a esperar antes de que se inicie el proceso de cerrado del sistema. Ejemplos: shutdown -r +15 Empezar a apagar el sistema dentro de 15 minutos y una vez terminado, reiniciar. shutdown -h now Apagar el sistema inmediatamente, y detenerse cuando se termine el proceso. 1.3 Conceptos básicos. En primer lugar, y como mencionamos antes, UNIX es case sensitive: se distinguen mayúsculas de minúsculas. Por otro lado, UNIX es full duplex : los caracteres que se tipean, se envı́an al sistema, el cual los pasa a la terminal. Este proceso, conocido como eco, los copia directamente a la pantalla, aunque en ciertas ocasiones se desactiva (por ejemplo, para tipeo de claves). Los caracteres pueden clasificarse en dos grupos: Sección 1.3. Conceptos básicos. 8 • Caracteres comunes. • Caracteres de control. Los caracteres tipeados son examinados e interpretados antes de llegar a su destino. Todos los caracteres se transmiten a la terminal, excepto que el echo esté apagado. Los caracteres se almacenan en el núcleo hasta que se presiona <ENTER>. Cuando un caracter es precedido por el caracter \ (barra invertida), descarta este caracter y almacena el siguiente caracter como uno común sin otra interpretación. Al presionar <ENTER>, los datos almacenados se enviarán al programa que esté leyendo datos de la terminal. Los caracteres serán leı́dos aunque el núcleo esté ocupado con otras tareas. Para obtener ayuda acerca de algún comando, usar el comando: man <nombre-del-comando> que despliega la manual page para ese comando. Lo primero que se recomienda hacer es ejecutar man man es decir, ver la manual page del mismo man. Para volver al prompt mientras se visualiza una manual page presionar <q>. Finalmente, en la filosofı́a UNIX, solo existen archivos (una secuencia de bytes) y procesos (programas en ejecución). Ambos se organizan en estructuras jerárquicas. De esta manera, para el sistema, el teclado, la diskettera, etc. son archivos. 1.3.1 Caracteres de control en la lı́nea de comandos. Vamos a comentar algunos caracteres de control útiles al tipear en la lı́nea de comandos. Solo mencionamos los más útiles, aunque la lista completa se puede ver de [3]. <CTRL-A> Va al comienzo del texto. <CTRL-E> Va al final del texto. <CTRL-B> Mueve el cursor un caracter a la izquierda. <CTRL-F> Mueve el cursor un caracter a la derecha. <ALTL-B> Va al comienzo de la palabra anterior. <ALTL-F> Va al comienzo de la palabra siguiente. Sección 1.3. Conceptos básicos. 9 <CTRL-L> Limpia la pantalla. <ALTL-U> Pone toda la palabra en mayúscula. <ALTL-L> Pone toda la palabra en minúscula. <CTRL-K> Borra hasta el final de la lı́nea. <TAB> Completa la cadena incompleta. Es un caracter muy útil particularmente para trabajar rápidamente con nombres de archivos largos. También es útil el manejo de la salida por pantalla: <CTRL-C> Interrumpe la ejecución de un programa. <CTRL-S> Pausa una salida. <CTRL-Q> Continua mostrando una salida pausada. 1.3.2 Directorios. Los directorios son un tipo de archivo que permiten agrupar jerárquicamente archivos. Permiten mantener unida información relacionada. Cada usuario tendrá un home directory, o directorio de login, donde podrá mantener sus archivos. Al iniciar una sesión se posiciona al usuario en este directorio. A diferencia del home directory, hablaremos del working directory para referirnos al directorio en el cual se está posicionado. Mientras que el working directory cambia al cambiar de directorio, el home directory se mantiene invariable para un usuario del sistema. Los directorios privados de los usuarios del sistema suelen estar en /users o /home. Comandos para administrar directorios. Describiremos los comandos básicos. cd <nombre-de-directorio> Hace que el working directory sea el directorio especificado. Sección 1.3. Conceptos básicos. 10 mkdir <nombre-de-directorio> Crea un directorio. rmdir <nombre-de-directorio> Elimina un directorio que no contiene archivos. pwd Print Working Directory. Imprime la ruta del directorio en el cual se está posicionado. echo $HOME Imprime en contenido de la variable de ambiente $HOME, que contiene la ruta del home directory. Más adelante hablaremos de variables de ambiente. Jerarquı́a de directorios. El directorio de máximo nivel es el / (llamado root —¡nada que ver con el usuario root!). Allı́ se encuentran una serie de directorios, que describiremos a continuación: /bin Acá se encuentran los programas básicos. /dev Acá se encuentran los dispositivos (terminales, impresoras, etc.). Hablaremos de dispositivos más adelante. /etc Contiene archivos y programas de administración. Solo por mencionar algunos: passwd es un archivo que contiene datos de los usuarios, rc se ejecuta al iniciar el sistema. /lib Biblioteca. Contiene principalemente partes del compilador C, preprocesador de C y, por ejemplo, libc.a que es la biblioteca de subrutinas de C. /tmp Temporales. Contiene archivos de vida corta. Por ejemplo, cuando se edita un programa, se crea en este directorio un archivo de trabajo, que es una copia del original. Este directorio se depura periódicamente. /usr Sistema de archivos de usuario. Contiene esencialmente los directorios descriptos hasta ahora, con los mismos significados, pero con programas menos vitales para el funcionamiento del sistema. Por ejemplo, el compilador FORTRAN está en /usr/lib. Vale la pena invertir un tiempo en recorrer estos directorios para estar más familiarizado con el sistema. Sección 1.3. Conceptos básicos. 1.3.3 11 Permisos. Cada archivo tiene un conjunto de permisos asociados, que determinan que se puede hacer y quien puede hacerlo. Cuando un usuario ingresa al sistema, éste lo reconoce por un número llamado user id (o identificador de usuario). Diferentes nombres de usuario pueden tener el mismo user id — aunque no es algo muy deseable, desde el punto de vista de la seguridad. Además de este valor, se le asigna al usuario un group id, que lo coloca dentro de una cierta clase de usuarios. El sistema usa estos dos valores para determinar los permisos para un usuario en relación con un archivo. Los permisos de un archivo pueden permitir: • leer, • escribir, y/o • ejecutar el archivo. Estas acciones se representan por r, w, x, respectivamente (debido a read, write, execute), y cada una se asigna a: • el usuario mismo, • el grupo al que pertenece el usuario, y • al resto de los usarios. Esta clasificación se representa por u, g, o, respectivamente (debido a user, group, others). Por ejemplo, supongamos que el archivo arch tiene los siguiente permisos: rwx rw- r--. Esto significa que el usuario puede leer, escribir (modificar) y ejecutar el archivo; que los usuarios del grupo al que pertenece pueden solo leerlo y modificarlo; y que el resto de los usuarios solo pueden leerlo. Para ver los permisos de un archivo, usar el comando: ls -l [<nombre-del-archivo>] Los corchetes indican que el parámetro no es necesario. Hablaremos más acerca de este comando más adelante. Cambiando los permisos de un archivo. El comando chmod (change mode), permite cambiar permisos de archivos, con el siguiente formato: Sección 1.3. Conceptos básicos. 12 chmod <permisos> <archivos> Solo el dueño de un archivo puede cambiar los permisos de un archivo. El parámetro <permisos> puede darse de varias maneras. Esencialmente hay dos: • Con sı́mbolos representativos. Usando las seis letras definidas antes, y usando + o para indicar si se dá el permiso, o si se quita, respectivamente. Por ejemplo: chmod u+x arch Le da permiso de ejecución del archivo arch al usuario. chmod ug+w-r arch Les da permiso de modificación al usuario y al grupo del archivo arch, pero les quita simultáneamente permiso de lectura. • Con números octales. Para cada clasificación se puede asignar una combinación de tres permisos, resultando en 23 = 8 alternativas distintas, lo cual sugiere una representación en base octal para los permisos. El “bit” de lectura (r) se define como el bit más significativo. Ası́, los permisos rw- se representan por el número octal 4 + 2 + 0 = 6. Por ejemplo: chmod 640 arch Le asigna los permisos rw- r-- --- al archivo arch, es decir, lectura y modificación para el usuario, lectura para el grupo al que pertenece el usuario, y ningún permiso al resto de los usuarios. El parámetro archivos puede ser uno o varios archivos separados por espacio o con wildcards— que explicaremos más adelante. Tener presente que el usuario root tiene permiso para todo. Capı́tulo 2 El Shell. Como ya se mencionó antes, cuando un usuario se conecta al sistema, éste presenta un prompt donde se tipean los comandos que el sistema pasa a ejecutar. No es el kernel el que dirige al usuario, sino un intérprete de comandos o shell, que es un programa que realiza la interpretación de los caracteres ingresados. A continuación hablaremos de las ventajas que presta este intérprete entre el sistema operativo y el usuario. 2.1 Uso de abreviaturas: Metacaracteres. Es posible referirse a una serie de archivos mediante el uso de metacaracteres, los cuales son interpretados por el shell antes de ser pasados al comando en cuestión. Los siguientes son metacaracteres: ? Un caracter cualquiera. * Cualquier cadena de caracteres. [conjunto] Cualquier caracter del conjunto. [!conjunto] Cualquier caracter que no este en el conjunto. Ejemplos. Supongamos que creamos los directorios Mayo2001, Junio2001, . . . , Mayo2002. Si que quieren eliminar todos los directorios del año 2001: 13 Sección 2.1. Uso de abreviaturas: Metacaracteres. 14 rmdir *2001 En este caso, el shell sustituye el metacaracter * por Mayo, Junio, etc., y es ésto lo que le pasa al comando rmdir. Es decir, desde el punto de vista del comando rmdir, es como que el usuario hubiese tipeado rmdir Mayo2001 Junio 2001 etc., con todos los direcctorios que correspondan. Si se quieren eliminar los meses Junio y Julio: rmdir Ju?io* El shell reemplaza el metacaracter ? por n y l respectivamente, y el * por 2001, que son las cadenas que corresponden a los archivos del directorio actual, y es ésto lo que le pasa al comando. Nuevamente, desde el punto de vista del comando rmdir, es como si no se hubieran usado metacaracteres, porque él no los vé. Notar que el uso de metacaracteres simplifica el diseño de los comandos. De no existir el shell, habrı́a que implementar para cada comando la interpretación de metacaracteres. Ahora, supongamos que tenemos los archivos arch1, arch2, . . . , arch9. rm arch[1-46-9] Elimina todos los archivos, salvo el archivo arch5. Como siempre, el comando no vé los metacaracteres, sino que vé los parámetros arch1, . . . , arch4, arch6, . . . , arch9. rm [a-z] El comando rm informarı́a que no encuentra ningún archivo para borrar, pues no hay archivos cuyos nombres sean exclusivamente caracteres de la a a la z. rm [a-z]8 Borra el archivo arch8. rm *[!8] Borra todos los archivos, salvo arch8. 2.1.1 Nombres de archivos con metacaracteres. Inmediatamente surje la pregunta de si es posible tener archivos que tengan metacaracteres en sus nombres, por ejemplo, arch*. Esto es posible, y si uno no quiere que el shell interprete un metacaracter, debe anteponerle el metacaracter \ o escribir el metacaracter entre apóstrofes. Nos referiremos (informalmente) a esta acción como casteo de un caracter. Por ejemplo: rm arch Borra el archivo arch*, y no todos los archivos cuyo nombre comiencen con arch. rm arch’*’ Tiene el mismo efecto que el anterior. Sección 2.2. Variables de Ambiente. 2.2 15 Variables de Ambiente. Algunas propiedades del shell son controladas por una serie de variables de éste, que llamaremos variables de ambiente. Algunas variables que tı́picamente usa el shell son: HOME contiene el home directory del usuario. PATH contiene la lista de directorios, separados por ’:’, donde el shell busca los comandos a ejecutar. Colocar ’.’ o nada antes de los primeros o últimos ’:’ indica working directory, aunque suele no setearse por seguridad. SHELL contiene el shell que se está ejecutando. PWD contiene el working directory. TERM contiene el tipo de terminal. Ciertos programas lo utilizan para manejar más eficientemente la pantalla. 2.2.1 Obteniendo el valor de variables. Obtener el valor de una variable es la acción de indicarle al shell que interprete el contenido de la variable. Los valores de variables se abtienen anteponiendo el caracter $ al nombre de la variable. Por ejemplo, para ver el contenido de una variable, se puede hacer: $ echo $HOME El caracter $ en negrita antes del comando echo representa el prompt del shell, y no debe ser tipeado. De aquı́ en adelante seguiremos esta convención. Para agregar un directorio a la variable de ambiente PATH, se puede hacer: $ PATH=$PATH:/user/games 2.3 Variable de usuario. Como convención, las variables de ambiente llevan nombres en mayúsculas. Uno puede definir variables propias, usando nombres en minúsculas. Sección 2.3. Variable de usuario. 16 Por ejemplo, si uno accede muchas veces a un determinado directorio, podrı́a hacer: $ midir=/nombre/de/directorio/terriblemente/largo y simplemente ejecutar: $ cd $midir Notar que el auto-completado con la tecla <TAB> también funciona con variables. 2.3.1 Sustitución. Ya vimos que el shell reemplaza $var por el valor del string asignado a la variable. También, una variable está configurada, si alguna vez le ha sido asignado un valor, siendo válido el string nulo como valor para una variable. Nos centramos ahora en sustituir el valor de una variable, dependiendo de si ésta tenı́a o no un valor asignado. Sustitución incondicional. En este caso, si la variable tenı́a valor, se pierde. ${variable#patron} ${variable##patron} Si patron coincide con el comienzo del valor de variable , el valor de sustitución es el valor de variable con la parte coincidente eliminada. En el primer caso se reemplaza la menor parte coincidente y en el segundo, la mayor parte coincidente. ${variable%patron} ${variable%%patron} Si patron coincide con el final del valor de variable , el valor de sustitución es el valor de variable con la parte coincidente eliminada. En el primer caso se reemplaza la menor parte coincidente y en el segundo, la mayor parte coincidente. Sustitución condicional. ${variable:-cadena} Si variable está asignada y no es nula el valor de sustitución es el valor de variable , sino el valor de sustitución es cadena . Sección 2.4. Entrecomillado. 17 ${variable:=cadena} Si variable está asignada y no es nula el valor de sustitución es el valor de variable , sino el valor de sustitución es cadena , y le asigna este valor a variable . ${variable:+cadena} Si variable está asignada y no es nula el valor de sustitución es el valor de cadena , sino el valor de sustitución es nulo. ${variable:?cadena} Si variable está asignada y no es nula el valor de sustitución es el valor de variable , sino el valor de sustitución es cadena , y sale al shell. Si cadena es omitido, se imprime el mensaje parameter null or not set. Si se lo utiliza en un .profile no sale del sistema. Sirve para verificar si las variables están seteadas. Los : en la sustitución de variable significa opcional. 2.4 Entrecomillado. El entrecomillado se utiliza para indicarle al shell que un string, que de otra forma se interpretarı́a como partes separadas, debe ser interpretado como una unidad. Por ejemplo, un archivo puede llamarse archivo con nombre largo.txt. El contenido de un archivo puede mostrarse por la salida standard utilizando el comando cat. Si tipeamos: $ cat archivo con nombre largo.txt El shell le pasarı́a al comando cat los parámetros archivo, con, nombre y largo.txt por separado. Para que el shell le pase un único parámetro deberı́amos tiperar: $ cat ’archivo con nombre largo.txt’1 2.4.1 Tipos de entrecomillado. Distinguimos 3 tipos de entrecomillado: Comillas. El shell interpreta caracteres especiales. 1 También se podrı́an castear los espacios. Sección 2.5. Redireccionamiento de la Entrada y Salida. 18 Apóstrofe. El shell no interpreta caracteres especiales. Acento grave (como en à). El shell ejecuta el comando y pasa la salida. Por ejemplo: $ mivar=’es una’ $ echo ’esto $mivar prueba’ esto $mivar prueba $ echo "esto $mivar prueba" esto es una prueba $ echo ‘date‘ Mar, 20 Ago 2002 01:26:43 GMT-03:00 2.5 Redireccionamiento de la Entrada y Salida. La idea de redirección está sustentada por el concepto que ya mencionamos, en el que todo en definitiva es un archivo. Muchos de los comandos que se describirán en capı́tulos posteriores, toman su entrada de la entrada standard o producen su salida por la salida standard. Es común que se desee, por ejemplo, la salida de un comando no salga por la salida standard sino que se almacene en un archivo de texto. Lo mismo ocurre para la entrada de datos a un comando: puede ser deseable que el comando no espere datos desde la entrada standard sino que los tome desde un archivo. Los caracteres > y < permiten la redirección de la salida y la entrada de comandos a o desde archivos, respectivamente. 2.5.1 Ejemplos. $ cat arch1 arch2 arch3 Este comando concatena los tres archivos2 por la salida standard. $ cat arch1 arch2 arch3 > total Este comando concatena los tres archivos y esta salida se guarda en el archivo total. Nada se imprime en la salida standard. Si el archivo de redirección no existe, lo crea. Si existe, lo sobreescribe. Notar que es el shell el que se encarga de este redireccionamiento. Es decir, el comando cat simplemente hace su tarea de concatención, desentendiéndose de cual será el destino. 2 Es decir, imprime consecutivamente el contenido de los tres archivos en el orden indicado. Sección 2.6. Interconexión. 19 $ cat arch1 arch2 arch3 >> total Esto tiene el mismo efecto que en el caso anterior, con la diferencia que si el archivo de redirección existe, no lo sobreescribe, sino que hace un append. $ cat arch $ cat < arch Si bien, ambos casos producen el mismo resultado, en el primer caso, el comando “ve” que tiene que trabajar con el archivo arch. En el segundo caso, en cambio, es el shell quien le pasa el contenido del archivo al comando, y por lo tanto el comando “no se entera” de que trabaja con el archivo, y a sus efectos, “ve” simplemente una entrada standard. Este ejemplo se menciona con el fin de marcar esta, si bien sutil, diferencia entre ambos casos. $ comando-cualquiera 2> archivo-de-errores Para cada proceso de un sistema UNIX se asignan tres descriptores de archivo: entrada standard, salida standard, salida standard para errores. Los dos primeros casos ya los vimos antes. El tercer caso, se refiere a los mensaje de error, que por defecto se imprimen por la terminal. En muchos casos esto no es deseable3 . Para esto es que el shell interpreta a 2> como redireccionamiento de la salida standard para errores. Es decir, cualquier mensaje destinado a la salida standard para errores no se imprimirá en la terminal, sino que se imprimirá en el archivo archivo-de-errores. $ comando-cualquiera 2> /dev/null Esencialmente ocurre lo mismo que antes, aunque en este caso, la redirección es hacia el archivo /dev/null, el cual representa un archivo nulo: cualquier secuecia de caracteres redireccionado a este archivo será eliminado sin posibilidad de recuperación. Para hacer una analogı́a, es una suerte de papelera de reciclaje. $ comando-cualquiera << EOF El comando toma su entrada desde la entrada standard hasta que se ingrese EOF. 2.6 Interconexión. La sección anterior se centró en el problema de redireccionamiento. Con esto solo, si se quisiera conectar dos comandos, se deberia redireccionar la salida de uno a un archivo temporal y que el segundo comando tome como entrada este archivo. 3 Por ejemplo, en casos en que se deba llevar un log de los errores o el avance del programa. Sección 2.6. Interconexión. 20 Una de las grandes contribuciones de un sistema operativo UNIX es la posibilidad de interconectar dos procesos sin necesidad de utilizar archivos temporales auxiliares. Esto se consigue con el caracter |. $ who | sort Este ejemplo es con fines ilustrativos. El comando who imprime por la salida standard los usuarios loggeados al sistema. El comando sort4 ordena el archivo que se le especifica. La salida del who no se imprime por la salida standard, sino que se imprime la del sort, cuya entrada es la salida del comando who. En esta instancia, debe quedar claro que el objetivo y el propósito de tener estar herramientas brindadas por el sistema, es tener comandos simples, que al interconectarlos produzcan efectos más sofisticados. En capı́tulos posteriores, veremos como lograr esto, mediante lo que se llaman scripts, para luego ver en detalle el funcionamiento de comandos en detalle. 4 El comando sort se describe en detalle más adelante Capı́tulo 3 Programación con el Shell: Shell-Scripting. En el caso más simple, un script es un archivo con permiso de ejecución que contiene una serie de comandos que serán ejecutados secuencialmente. Esto salva de estar tipeando esa secuencia de comandos cada vez que se invoca al script. Shell-Scripting se remonta a la filosofı́a clásica de UNIX de separar o dividir un problema grande en problemas más pequeños. 3.1 Comentarios. El caracter # es el más utilizado para comentarios en shell : éste ignora todo lo que viene después del caracter numeral. Por ejemplo: $ echo hello # there hello $ echo hello#there hello#there El caracter : también es de comentarios, pero debe usarse al principio de la lı́nea. En verdad, éste es el comando null del shell. 3.2 Argumentos y Parámetros. El comando shift. Los parámetros de posición son usados para pasar argumentos desde la lı́nea de comandos a los scripts. De la misma manera que con las variables, los valores de parámetros se obtienen con el caracter $ y el dı́gito que indica su posición, siendo $0 siempre el nombre del comando. 21 Sección 3.2. Argumentos y Parámetros. El comando shift. 22 El shell bsh no permite trabajar con más de 10 parámetros directamente, es decir, interpreta a $10 como el parámetro uno seguido del caracter cero. Para ello se utiliza el comando shift. Lo que hace shift es pasar el contenido de $1 a $0 y ası́ siguiendo, perdiendo el valor original de cada variable. El siguiente es un ejemplo ilustrativo que imprime los argumentos que se pasan al script como parámetros: while [ ! -z $1 ] do echo $1 shift done La sentencia while y la expresión de testeo se explican en las secciones 3.5.2 y 3.3 respectivamente. 3.2.1 Parámetros especiales. Supongamos que se ejecuta: $ prog a b c Entonces vale: $0 prog $# 4 $* a b c seguido de los archivos del working directory "$*" a b c * $$ id del proceso padre $! pid del último comando ejecutado en background $? estado del último comando ejecutado en foreground $opciones del shell en efecto Sección 3.3. Pruebas. El comando test. 3.2.2 23 Estado de salida. El comando exit. Cada vez que un programa completa su ejecución, retorna un estado al sistema. Este estado es un número que indica si el programa ha sido ejecutado existosamente o no. Por lo general, el estado cero indica ejecución exitosa y todo valor distinto de cero indica que la ejecución ha fallado. Esto permite, además de la verificación del resultado del programa, el control del mismo en el manejo de errores y progresión de la ejecución. Como se menciona en el apartado anterior, para ver el estado de salida, basta ver el valor de $? inmediatamente después de la ejecución del proceso en cuestión. Para hacer que un script termine devolviendo un estado en particular, se utiliza el comando exit n , siendo n el código de terminación. Si no especifica este parámetro, se devolverá el del último comando ejecutado. 3.3 Pruebas. El comando test. El comando test permite evaluar el valor de verdad de expresiones lógicas, devolviendo cero en caso de éxito, o distinto de cero en caso contrario. El formato de este comando1 es: test expresión o [ expresión ] expresión contendrá un conjunto de operadores que describiremos a continuación, según la prueba. También, expresión debe estar rodeada por espacios y debe entrecomillarse para embeber los espacios dentro de ella. 3.3.1 Operadores del comando test. ! . . . . . . negación -a . . . . . . AND -o . . . . . . OR 3.3.2 Pruebas sobre archivos. Algunos tipos de prueba sobre archivos son: 1 ]]. tanto para Bourne Shell como para Korn Shell, permitiendo este último la prueba mediante [[ expresión Sección 3.4. Aritmética entera. El comando expr. -a file -d file -f file -L file -p file -s file -r file -w file -x file file1 -nt file2 file1 -ot file2 3.3.3 A A A A A A -eq -ge -gt -le -lt -ne 3.3.4 24 . . . . . . file existe. . . . . . . file existe y es un directorio. . . . . . . file existe y es un archivo regular. . . . . . . file existe y es un link simbólico. . . . . . . file existe y es una named pipe. . . . . . . file existe y no es vacı́o. . . . . . . file existe y tiene permiso de lectura. . . . . . . file existe y tiene permiso de escritura. . . . . . . file existe y tiene permiso de ejecución. . . . . . . file1 es más nuevo que file2 . . . . . . . file1 es más antiguo que file2 . Prueba de valores para operaciones algebraicas. B B B B B B . . . . . . igual a . . . . . . mayor o igual a . . . . . . mayor a . . . . . . menor o igual a . . . . . . menor a . . . . . . distinto de Prueba de valores para cadena de caracteres. Debido a que una cadena puede contener nulos o espacios intermedios, siempre es aconsejable entrecomillar a la variable con comillas dobles para evitar errores en el comando test. string1 = string2 . . . . . . las cadenas son iguales string1 != string2 . . . . . . las cadenas no son iguales string . . . . . . la cadena no es nula -z string . . . . . . la cadena tiene longitud cero (es nula) -n string . . . . . . la cadena no es nula 3.4 Aritmética entera. El comando expr. En Bourne Shell, todas las variables son strings. Las operaciones matemáticas entre strings no son posibles, pero existe una forma de evaluar una expresión tipo string como una expresión matemática, utilizando el comando expr. expr evalúa sus argumentos como una expresión matemática y devuleve el resultado a la salida standard. Las operaciones disponibles son: +, -, *, % (resto) y /. Cuando se utilicen estos operadores deberá haber un espacio a ambos lados del mismo. Sección 3.5. Comandos de control. 25 Hay también una operación de equiparación, :, que compara el primer argumento con el segundo. El segundo debe ser una expresión regular (a ver más adelante). La operación retorna el número de caracteres coincidentes, o cero si no hay coincidencia. Al utilizar una expresión regular coincidente con todo, .*, el operador de equiparación puede ser usado para determinar la longitud del primer argumento. Si se ejecuta una expresión entre comillas simples, el resultado reemplaza a la expresión misma. Recordar que $, *, etc., deben estar casteados para que no sean interpretados por el shell. Ejemplo. $ $ $ 3 a=’expr 1 + 2’ b=’expr $a \* 4’ echo $a $b 12 3.4.1 Operador de longitud. ${#variable} Devuelve la longitud de variable . 3.5 Comandos de control. Los comandos de control pueden dividirse en dos grupos: • sentencias de decisión • sentencias de iteración 3.5.1 Sentencias de Decisión. Sentencia if. Formato: if condición then comandos [elif condición then comandos ] Sección 3.5. Comandos de control. 26 [else comandos ] fi Ejemplo. El siguiente script determina si el archivo pasado como parámetro existe y tiene un tamaño mayor a cero. if test -s "$1" then echo $1 es un archivo existente con tama~ no mayor a cero. else echo $1 no existe o tiene tama~ no nulo. fi Sentencia case. Es utilizada para la selección de múltiples alternativas. Cada posibilidad es conocida como branch y cada branch debe estar separada por ;;, siendo opcional en el último branch. La variable en la sentencia case debe ser una coincidencia explı́cita: no debe haber expresiones regulares o nombres de archivos referenciados con comodines. Sı́ es posible usar la condición OR que puede ser utilizada en los patrones, representada por |. Los metacaracteres pueden usarse en los patrones con el siguiente significado: • * : cero o más ocurrencias de uno o todos los caracteres. • ? : cualquier caracter. • [] : configura y determina rangos. Formato: case valor in pat1) comandos ;; pat2) comandos ;; ... patN) comandos Sección 3.5. Comandos de control. 27 ;; *) comandos por defecto ;; esac Ejemplo. El siguiente script muestra un pequeño menú para determinar que hacer con el archivo pasado como parámetro. if test $# then Uso: $0 exit 1 # fi if test ! -ne 1 # verificamos que se pase un parámetro archivo # $0 es el nombre del script salimos devolviendo un código de terminación de error por uso erróneo -f "$1" # verificamos la existencia del archivo then echo $1 no es un nombre de archivo válido. exit 2 # salimos devolviendo un código de terminaci’on de error por archivo no válido fi echo ¿Qué desea hacer con $1?: # presentamos un menu echo echo echo read ’<I> para imprimirlo.’ ’<B> para borrarlo.’ ’<otra-tecla> para salir.’ accion # leemos la opcion que se ingrese case $accion in I|i) lp $1 ;; B|b) rm $1 ;; *) echo Saliendo sin hacer nada... esac ;; En este ejemplo se introdujeron los comandos read, para leer de la entrada standard el valor para una variable, y el comando lp para formatear e imprimir archivos. Sentencia select. Esta sentencia, solo disponible en Korn Shell, permite un listado de selección por menú. Este comando usa la variable de ambiente PS3 para el prompt, y COLUMNS y LINES para determinar la apariencia del menú. Sección 3.5. Comandos de control. 28 Formato: select variable in arg1 arg2 ...argN do comandos done El usuario selecciona el elemento de la lista sobre la cual ejecutará los comandos , los cuales se continuarán ejecutando hasta que se encuentre con comandos de ruptura, tales como break, exit o return. Ejemplo. PS3="Elija uno: " select i in 6109 6110 6620 7506 7542 exit do case $i in 6109) echo $1 Probabilidad y Estadistica B ;; 6110) echo $1 Analisis Matematico III ;; 6620) echo $1 Organizacion de Computadoras ;; 7506) echo $1 Organizacion de Datos ;; 7542) echo $1 Taller de Programacion I ;; exit) echo Saliendo... exit 0 ;; *) echo Seleccion invalida ;; esac read rta?"Continuar? (s/n)? " if [ $rta != ’s’ ] then echo Fin del menu exit 0 fi done 3.5.2 Sentencias de Iteración. Sentencia for. Formato: for variable in lista do Sección 3.5. Comandos de control. 29 comandos done o alternativamente for variable in lista ; do comando1 ; ...; comandoN ; done La lista puede ser enunciada explı́citamente o ser el resultado de otro comando o metacracteres. Para cada iteración, variable toma el valor de cada uno de los elementos de lista , concluyendo el ciclo cuando se llegue al último elemento de lista . Sentencia while. Esta sentencia ejecuta los comandos mientras la condicion sea verdadera. Formato: while condicion do comandos done Sentencia until. Esta sentencia cicla hasta que condicion se cumpla. Formato: until condicion do comandos done Hasta acá se tienen vistas varias de las herramientas que brinda el sistema. Pasaremos ahora a estudiar comandos simples en detalle. Capı́tulo 4 Comandos de Entrada y Salida. Estudiaremos ahora comandos del sistema en detalle. Dado que muchos de ellos incluyen opciones muy especı́ficas y fuera del alcance de este apunte, se sugiere consultar las manual pages correspondientes para mayor información. 4.1 Traducción de caracteres: el comando tr. El comando tr es un filtro utilziado para traducir los caracteres desde la entrada standard hacia la salida standard. Sintaxis: tr [charset1 ] [charset2 ] Notar que la sintaxis no especifica archivos. Para trabajar con archivos, el ingreso debe ser redireccionado desde la lı́nea de comandos. Los rangos y conjuntos pueden ser utilizados como un mapeo de caracteres de uno en uno. Si charset2 es más corto que charset1 , entonces charset2 es completado con la repetición del último caracter en el conjunto. 4.1.1 Ejemplos. Para el ejemplo utilizaremos el siguiente archivo, que llamaremos arch: Mercurio Urano Tierra Marte Neptuno G. B. F. B. T. Total Total Total Total Total horas horas horas horas horas 80 78 80 40 80 $ tr 8 2 < arch 30 Sección 4.2. El comando cut. Mercurio Urano Tierra Marte Neptuno G. B. F. B. T. Total Total Total Total Total horas horas horas horas horas 31 20 72 20 40 20 $ tr [a-z] [A-Z] < arch MERCURIO URANO TIERRA MARTE NEPTUNO 4.2 G. B. F. B. T. TOTAL TOTAL TOTAL TOTAL TOTAL HORAS HORAS HORAS HORAS HORAS 80 78 80 40 80 El comando cut. El comando cut puede ser usado para cortar columnas desde una tabla o campos de un archivo. Los campos cortados no necesariamente tiene que ser de longitud fija. Sintaxis: cut -lista [arch1 arch2 ...archN ] Si no se le indica ningún archivo, toma como entrada la entrada standard. El modificador lista puede ser: -ci -ci,j,k -ci-j -ci - El caracter i -ésimo. Los caracteres i -ésimo, j -ésimo y k -ésimo. Desde el caracter i -ésimo hasta el j -ésimo. A partir del caracter i -ésimo. El comando cut empieza a contar los caracteres desde 1. Esto funciona muy bien en los archivos que posean un formato bien definido, como la salida del comando who1 . Como alternativa se tiene la especificación de campos a cortar: • Con la opción -dcaracter se le especifica al comando cut el caracter que debe tomar como separador de campos. • La opción -flista especifica el campo o campos que serán cortados. • La opción -s indica que no se impriman aquellas lı́neas que no contienen al separador de campos. 1 El comando who lista información sobre los usuarios loggeados al sistema. Los nombres de usuario son los caracteres del 1 al 8, las terminales son del 12 al 24 y las fecha y hora del login son del 25 al 36. Sección 4.3. El comando paste. 4.2.1 32 Ejemplos. $ who root user1 user2 user3 term/01 term/00 term/02 term/03 Apr Apr Apr Apr 12 12 12 12 08:00 09:01 09:13 09:15 $ who | cut -c1-5 root user1 user2 user3 $ who | cut -c1-5,19root user1 user2 user3 Apr Apr Apr Apr 12 12 12 12 08:00 09:01 09:13 09:15 Sea ahora el archivo infou: root:x:0:0:Super User:/:/bin/ksh cron:NONE:1:1:Time Daemon:/: user1::100:101:555 1212:/home/user1:/bin/sh $ cut -d: -f1,6 infou root:/ cron:/ user1:/home/user1 4.3 El comando paste. El comando paste funciona en cierta forma a la inversa del comando cut: yuxtapone columnas. Distinas sintaxis: paste arch1 arch2 ...archN Esta es la forma más simple de uso, en la que cada lı́nea de cada archivos se ponen juntas separadas por una tabulación. Sección 4.3. El comando paste. 33 paste -d lista arch1 arch2 ...archN En este caso, en lugar de utilizar el separador por defecto, paste utiliza como separadores los caracteres indicados en lista . paste -s [-d lista ] arch1 arch2 ...archN Se utiliza para pegar lı́neas dentro de un mismo archivo. paste - arch1 [arch2 ...archN ] Indica que además de los archivos indicados, debe tomar una entrada que le está siendo redireccionada. 4.3.1 Ejemplos. Supongamos los siguientes tres archivos: ciudades Atlanta New York Los Angeles nombres user1 user2 user3 telefonos (404)555-5356 (212)555-3456 (213)555-1234 $ paste nombres telefonos user1 user2 user3 (404)555-5356 (212)555-3456 (213)555-1234 $ paste -d’=+’ nombres ciudades telefonos user1=Atlanta+(404)555-5356 user2=New York+(212)555-3456 user3=Los Angeles+(213)555-1234 $ paste -s nombres user1 $ cut -d: user2 user3 -f5 clientes1 | paste - clientes2 Capı́tulo 5 Expresiones Regulares. Las expresiones regulares (REs) son patrones que describen strings y se usan para matchear 1 esos strings. Las expresiones regulares permiten, por ejemplo, seleccionar algún conjunto de registros de un campo de un archivo de datos. El espectro de aplicación varı́a desde algo simple como el reemplazo por parte del shell del caracter * por todos los archivos de un directorio hasta matcheos más refinados como los que utilizan comandos como grep y awk. Las expresiones regulares se construyen a partir de caracteres ordinarios y metacaracteres. Los caracteres ordinarios se matchean a sı́ mismos, mientras que los metacaracteres matchean distintos grupos de caracteres o modifican la operación de otros caracteres. En UNIX tenemos tres tipos o niveles de expresiones regulares: 1. los del shell, para nombres de archivos, de los cuales ya se habló antes; 2. los simples, utilizados por comandos como grep y sed; 3. los extendidos, utilizados por comandos como egrep. Para los tres casos, se cumple: • La barra invertida \ se usa para castear un caracter, es decir, todo caracter que siga a una barra invertida se tomará como una caracter ordinario, inclusive si éste es un metacaracter. • Caracteres entre corchetes [] representan un solo caracter matcheado de todos los del conjunto. – Si el primer caracter de un conjunto es el acento circunflejo ^ se matchea el complemento del conjunto, es decir, todo lo no perteneciente al conjunto. – Si se utiliza el guión -, se está indicando un rango de caracteres. 1 En este apunte vamos a usar este término para significar corresponder o coincidir, por falta de un verbo que exprese más precisamente el verbo inglés to match. 34 Sección 5.1. Expresiones regulares simples. 35 Por Ejemplo. abcde [abcde] [a-e] [^a-e] \[\]\\ 5.1 Los caracteres ’a’, ’b’, ’c’, ’d’ y ’e’ se matchean en ese orden. Uno de los caracteres ’a’, ’b’, ’c’, ’d’ o ’e’ se matchean. Idem anterior. Un caracter, salvo ’a’, ’b’, ’c’, ’d’ o ’e’, se matchean. Los caracteres ’[’, ’]’, ’\’ se matchean en ese orden. Expresiones regulares simples. Aparte de los caracteres ya mencionados, las expresiones regulares simples brindan los siguientes metacaracteres: • El asterisco * significa repetir la RE anterior a él un número arbitrario de veces, incluyendo ninguna vez. • El punto . matchea un caracter cualquiera. • El acento circunflejo ^ en este caso está sobrecargado: solo tiene sentido como primer caracter de una RE, caso en el cual significa matchear el comienzo de la lı́nea. • El signo de pesos $ solo tiene sentido como último caracter de una RE, caso en el cual significa matchear el final de la lı́nea. El comando grep trabaja con llaves, cuando son casteadas, para denotar una cantidad de ocurrencias de la RE que precede: \{n\} \{n,\} \{n,m\} Exactamente n ocurrencias. Por lo menos n ocurrencias. Entre n y m ocurrencias. También, el editor vi trabaja con paréntesis angulares <> para indicar comienzo o final de una palabra, respectivamente. 5.1.1 Algunos ejemplos de expresiones regulares simples. p[aeo]lo Alguno de ’palo’, ’pelo’, ’polo’. ^$ Una lı́nea en blanco (matchear comienzo, nada, y fin). ^[a-zA-Z]$ Sección 5.2. Expresiones regulares extendidas. 36 Lı́neas de una sola palabra. ^[0-9]$ Lı́neas con exactamente un número. d.n Cualquier secuencia de tres caracteres comenzando con una ’d’ y terminando con una ’n’. d[aeiou]n ’dan’, ’den’, ’din’, ’don’, or ’dun’. 4[2-9][0-9][0-9]-[0-9]\{4\} Un nḿero telefónico del Gran Buenos Aires: un cuatro, un dı́gito entre dos y nueve, dos dı́gitos, un guión y cuatro dı́gitos. 5.2 Expresiones regulares extendidas. Las expresiones regulares extendidas agregan paréntesis para agrupar. • La barra vertical (o pipe) | para alternar. • El signo más + para repetir el item precedente por lo menos una vez. • El signo de interrogación ? para matchear el item precedente ninguna o una vez. 5.2.1 Ejemplos de REs Extendidas. (Andrea|Beatriz|Carla) (Dieguez|Fernandez) Matchea alguno de los seis nombres ’Andrea Dieguez’, ’Andrea Fernandez’, ’Beatriz Dieguez’, ’Beatriz Fernandez’, ’Carla Dieguez’ o ’Carla Fernandez’. [0-9]+ Matchea un número entero (uno o más dı́gitos). (\+|-)?[0-9]+ [+-]?[0-9]+ Matchea un número entero que puede o no llevar signo (un signo más, un signo menos o nada, seguido de un número entero). Further articles in this series will focus on various utilities which use REs to select data for processing–grep, egrep, sed, and awk. Referencias [1] Apunte de “Entorno UNIX” por Paola Chamoles. Año 1999. 75.08—Sistemas Operativos. [2] Red-Hat Official Installation Guide. http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/install-guide/ [3] Manual page del shell bash. 37