![]() |
|
![]() |
5.1 Hablando con GNU/Linux a través del shell
El shell o interprete de comandos, como antes habíamos dicho, es una interfase con nuestro sistema operativo. Gracias a él podremos dar las ordenes y mandatos necesarios para que nuestro sistema informático realice las tareas que necesitamos.
No debemos confundir al interprete de comandos con el sistema operativo. Este es solo un programa que hará de mediador entre nosotros y el kernel del sistema.
El shell puede ser tanto grafico (Ej. La interfase X-Window), como de texto (Ej. El bash).
En este capitulo trataremos el tema de shell al nivel de solo texto y en especial veremos un interprete de comando que por su utilidad y su gran aceptación, es él mas usado tanto en UNIX como en GNU/Linux.
Como veremos luego, el interprete de comandos no solo tiene la labor de interpretar nuestros mandatos, también es un potente lenguaje de programación que nos será de gran utilidad a la hora de elaborar guiones (script) para poder automatizar nuestras tareas. Los usuarios de DOS estarán acostumbrados a la utilización de los archivos de procesamiento por lotes (.bat) o más bien denomina "batch".
Existen varios tipos de interpretes de comandos en UNIX de los cuales los más famosos e importantes son el "Bourne Shell" sh y el "C Shell".El intérprete de comandos Bourne, usa una sintaxis de comandos usada en los primeros sistemas UNIX, como el System III. El nombre de interprete Bourne en la mayoría de los UNIX es /bin/sh (sh por shell).
El C Shell posee una sintaxis muy parecida al lenguaje de programación C y se lo encontrara como /bin/csh.
El mas usado, como antes dijimos, es el bash por "Bourne Again Shell y se lo encontrara en /bin/bash. Bash posee toda la funcionalidad del sh con características avanzadas de C Shell, por esto cualquier guión escrito para un interprete de comandos sh correrá perfectamente en él.
Si lo que se prefiere es el uso del interprete de comandos basado en el lenguaje C, en GNU/Linux se podrá encontrar el Tcsh, /bin/tcsh, que es una versión extendida del C Shell.
Los gustos de los usuarios son los que deciden que interprete de comandos se usara, por esto es posible configurar para cada usuario un interprete de comandos distintos y no afectar el funcionamiento de programas como el "ls", "cat" o "cp". Solo se vera afectada la funcionalidad de algún guión que este preparado para ejecutar con un interprete de comandos determinado, lo que veremos como se puede corregir al ver programación de script de shell.Para mas información respecto a cada uno de estos interpretes de comandos se recomienda leer las paginas de manual de cada uno de ellos, lo que dará información muy detallada de estos.
5.1.1: Características
Comodines:
Hablaremos de algunas característica de mucha utilidad y que harán mucho más fácil el trabajo, tanto en sh como en bash.
Una de las características que poseen los interpretes de comandos es el usado de comodines para reemplazar partes de archivos. Con esto, podría refreírse a un archivo usando caracteres especiales como el "*" o "?". Supongamos que se desea listar todos los archivos que contengan la letra "ñ" en nuestro directorio. Para ello usaremos el comando "ls":[sebas@LUSI]$ ls *ñ*
Esto el interprete de comandos lo vera como si quisiéramos listas todos los archivos que empezaran con ninguno, uno o varios caracteres, tuviesen una letra "ñ" y terminaran con ninguno, uno o varios caracteres.
[sebas@LUSI]$ ls
hola heart texto.form manti.form[sebas@LUSI]$ ls h*
hola heartComo puede observarse también nos es útil si se sabe como comienza el archivo pero no como termina. Lo que nuestro interprete de comando esta asiendo es sustituir el "*" con cualquier combinación posible que coincida con los ficheros que tenemos en el directorio donde estamos buscando.
Si se utiliza solamente el "*" con el comando "ls", este interpretara que se esta buscando cualquier combinación posible y listara todo como si se estuviese tratando de ejecutar el comando "ls" solo:[sebas@LUSI]$ ls *
hola heart texto.form manti.formEste proceso es llamado expansión de comodines y lo efectúa el interprete de comandos. Esto es muy importante ya que los comandos como el "ls" nunca ven el "*" en su lista de parámetros, es el interprete de comandos quien expande los comodines para incluir todos los nombres de ficheros que se adapten. Es decir que luego que se da la orden:
[sebas@LUSI]$ ls h*
es expandida para obtener
[sebas@LUSI]$ ls hola heart
Otro comodín es el "?". Este carácter comodín solo expande un único carácter. Luego "ls ?" mostrara todos los nombres de archivos con un carácter de longitud. En cambio la orden "ls hol?" nos mostrara el archivo "hola".
[sebas@LUSI]$ ls ho?a
hola
[sebas@LUSI]$ ls h????
heart
Estos caracteres comodín nos permiten referirnos a mas de un archivo al mismo tiempo y en conjunción con los comandos ya aprendidos, podrán ser de gran utilidad para realizar nuestras tareas de forma más fácil.
Ejecución de comandos uno detrás del otro:
Supongamos que se necesita ejecutar un comando e inmediatamente después otro.
En la forma común lo que haríamos seria ejecutar el primer comando y una vez que este haya finalizado, ejecutaríamos el segundo. Existe una segunda forma de hacerlo y es utilizando el carácter ";" inmediatamente después del primer comando y a continuación poner el segundo comando. Con esto lograríamos que se ejecutara el primer comando y al terminar se ejecutara el segundo.Ej: de un caso normal:
[sebas@LUSI]$ ls
hola heart texto.form manti.form
[sebas@LUSI]$ date
Sat Apr 15 14:17:01 ART 2000
Ej. Utilizando el carácter ";":
[sebas@LUSI]$ ls;date
hola heart texto.form manti.form
Sat Apr 15 14:17:01 ART 2000
Comillas:
Este punto viene bien aclararlo antes de empezar a ver características de alias y script para no tener complicaciones y confusiones.
En GNU/Linux existen tres tipos de comillas dobles ("), comillas sencillas (') y comillas inversas o tics inversos (`).
Empezaremos con las comillas inversas. Estas indican al shell que tendrá que remplazar lo que esta encerrado entre ellas con su resultado.
Supongamos que quisiéramos ver solamente el día de hoy.
Entonces teclearíamos el comando:[sebas@LUSI]$ date +%d
15
Ahora bien, cada vez que quisiéramos ver el día de hoy tendríamos que ingresar este comando nuevamente.
Si le asignamos a una variable de entorno el resultado, solo tendríamos que mostrar esta variable.[sebas@LUSI]$ DIAHOY=`date +%d`
[sebas@LUSI]$ echo $DIAHOY
15
(Hay que tener en cuenta que para asignarle un valor a una variable a una variable tenemos que solo poner un nombre seguido del signo "=" y luego lo que queramos ponerle dentro. En cambio para mostrarla tendremos que anteponerle el signo de dólar "$".)
Esto seria igual a poner:
[sebas@LUSI]$ diahoy=15
Lo único que el shell hace es expandir el comando para que solo se guarde el resultado de este.
El otro tipo de comillas, la sencilla ('), le dice al sistema que no haga ninguna expansión.
[sebas@LUSI]$ diahoy='date +%d'
[sebas@LUSI]$ echo $diahoy
date +%d
lo que se obtiene es exactamente lo que le asignamos a la variable ya que el shell no realizo ninguna expansión y lo único que asigno fue la cadena "date +%d" al a variable DIAHOY.
El ultimo tipo de comillas son las dobles, este tiene casi la misma funcionalidad que las comillas simples pero con la salvedad de que lo que se incluya dentro de estas pasara a ser como una cadena simple de caracteres. Los únicos caracteres que no son tomados son los tics inversos (`) el signo de dólar ($), la diagonal (\) y las mismas comillas dobles (").
Por ejemplo podríamos ingresar el siguiente comando:[sebas@LUSI]$ echo "`date`"
Sat Apr 15 14:17:01 ART 2000
Alias:
La utilización de alias nos da la capacidad de poder referenciar a un comando con otro nombre. La diferencia sustancial que podemos encontrar con los script de shell, es que los script para ejecutarse primero lanzaran a un subshell como un proceso hijo del shell que esta ejecutando en ese momento. En cambio un alias funciona en el proceso del shell siendo ejecutado en forma interna con la subsiguiente velocidad que esto otorga al no tener que crearse un nuevo proceso o de buscar en el disco rígido.
Por supuesto que pueden usarce un conjunto de comandos para crear otro más complejos. Con los scripts se puede realizar lo mismo y lo veremos mas adelante, pero para comandos simples y cortos no son necesarios.
Los alias pertenecen a cada usuario, pudiendo este configurarlos como más le convengan.
Supongamos que quisiéramos ver solo la hora cada vez que se lo pidamos al sistema y no quisiéramos poner el comando date con su modificador cada vez que lo queramos hacer. Lo que haremos será crear un "alias" al comando "date" con el modificador correspondiente. Para ello contamos con el comando alias, que seguido de argumentos nos permitirá crear uno, sin argumentos nos mostrara los alias que tenemos configurados.
[sebas@LUSI]$ alias hora='date +%r'
[sebas@LUSI]$ hora
02:45:04 PM
Ahora bien, esto funcionara mientras estemos en el sistema, ya que estos datos son cargados en memoria al salir del sistema se perderían.
Para que cada vez que entremos al sistema los alias sigan funcionando deberemos agregarlos a una archivo, que aparece en forma oculta en el directorio de cada usuario, denominado ".bash_profile" o en caso de que se requiera que el alias funcione para todos los usuarios en el /etc/bashrc.
Este archivo es leído por el /bin/bash cada vez que se entra al sistema.
En el se tendrá que poner la línea "alias" en igual forma que lo haríamos en la interfaz de comandos.Completado de línea :
Se puede hacer que el shell complete la línea de comandos cuando se introduzca la primeras letras y se presione la tecla [TAB].
Esta propiedad también es útil para expandir la ruta a un directorio determinado.
Ej.Supongamos que dentro del directorio /home existe un subdirectorio llamado /sebas
[sebas@LUSI]$ cd /home/se
Si presionamos la tecla [TAB] se completara la línea en /home/sebas.
Si existiera mas de un directorio que comenzara con "se", el shell anunciaría con una señal audible, "bip", que existen más de una coincidencia, y al presionar nuevamente la tecla [TAB] mostraría una lista de todos los directorios que poseen "se" al comienzo.
Con los comandos sucede algo parecido, a tal punto que si se oprimiera la tecla [TAB] sin haber introducido nada antes, el shell nos mostraría primero que existe un numero "X" de posibilidades y al presionar nuevamente nos mostraría un listado de todos los comandos que son alcanzables.5.1.2: PATH
Muchas veces ocurre que al tratar de introducir un comando nos damos cuenta de que no tiene efecto y nos da un error en él interprete de comandos. Tal vez se haya ingresado mal, pero tal vez no se posea el directorio que contiene dicho comando en la "ruta de búsqueda" o PATH.
EL PATH es una variable de entorno que contiene un grupo de directorios predefinidos en los cuales el shell buscara el comando o programa a ejecutar.
Esto ahorra tiempo ya que el sistema no tendrá que buscar en todos los directorios el programa a ejecutar. Por esto el sistema, en caso de que el directorio no figure en el PATH, no podrá ejecutar el programa hasta que le demos la ruta exacta en donde se encuentre.
Esta ruta se guarda en un archivo que se asignada a una variable de entorno llamada PATH, tema que veremos mas adelante, encuentra en un archivo del directorio /etc denominado profile que es solo modificable por el "root" y funciona como una referencia para todos los usuarios, además cada usuario posee en un archivo oculto denominado .bash_profile o .profile, donde se le asigna además del PATH inicial, cualquier otra modificación exclusiva para él. También puede modificarse totalmente esta variable.
Volviendo a la especificación de la ruta completa; anteriormente dijimos que los archivos se referenciaban de esta forma, pero los programas también podrán refenciarse de la misma forma. Si le damos la ruta completa podremos ejecutar el programa, si es que se cuenta con los permisos adecuados, referenciándolo con la ruta completa.
Como ejemplo, si quisiéramos ejecutar el programa date, referenciándolo con una ruta completa, la sintaxis seria así:[sebas@LUSI]$ /bin/date
Sat Apr 15 14:17:01 ART 2000
Seguramente el directorio /bin estará en nuestra ruta, esto sirve solo como un ejemplo.
Existe otra forma de arrancar el programa, y es haciendo referencia a su ruta relativa, que es la ruta con relación al directorio donde estamos pararos actualmente.
Para esto debemos saber que la forma de referenciar al directorio actual es mediante "." y a su directorio padre con ".." (Mencionándose comúnmente como "punto" y "punto - punto").
Dado que los directorios están divididos por una "/", se podría hacer referencia a u archivo en el directorio padre con "../archivo" .
De esta forma si se quisiera hacer referencia a un archivo que se encuentra dos niveles encima nuestro, su referencia relativa seria "../../archivo".Algo que difiere en la forma de ejecutar los archivos en GNU/Linux y DOS, es que este ultimo busca primero el archivo a ejecutar en el directorio actual y luego en la ruta de búsqueda. En cambio en GNU/Linux, solo se buscara en la ruta.
No es problema ejecutar un archivo que esta en el directorio actual ya que este esta incluido en la ruta, pero por seguridad, deberá estar agregado como el ultimo directorio en la ruta, por lo menos en la cuenta "root" ya que si algún usuario creara un archivo malicioso que estuviera en el directorio donde esta parado el usuario root en ese momento, y lo nombrara "more", cuando el root ejecute este comando tendría resultaos catastróficos. En cambio, si el directorio actual esta a lo ultimo de la ruta, primero se ejecutara el que se encontré en el /bin en lugar que el que esta en el directorio actual.
Igualmente para poder ejecutar directamente un programa que se encuentra en el directorio en que estamos parados actualmente podríamos ingresar la ruta relativa a este, anteponiendo la referencia al directorio actual "./" al programa.Ej. Para ejecutar el programa hola que se encuentra en el directorio donde estamos parados actualmente.
[sebas@LUSI /seba]$ ./hola
Hola amigos !!!
No busquen el programa "hola" en su sistema, no lo e distribuido aún ya que esta en desarrollo : )
5.1.3: Variables de entorno
Independientemente de shell que estemos usando, se contara con lo que se denomina "variable de entorno" o "variable de ambientes".
Estas variables son como las que encontraremos en cualquier lenguaje de programación; tan es de esta forma que también podría ser accedidas desde los scripts que creemos.
Para distinguir de los comando, la variables se ponen en letra mayúscula. Cuando uno entra al sistema, la mayoría de estas variables ya están asignadas.
Para ver estas variables y su contenidos se cuenta con el comando "set", y para ver el contenido de una de estas variables solo tenemos que usar el comando "echo" seguido del nombre de la variable con el signo "$" antepuesto. Ej. echo $LOGNAME, con lo obtendremos el nombre del usuario.Siguiendo con la ruta de búsqueda o PATH, esta es guardada en una variable llamada "$PATH", con lo que si tecleamos "echo $PATH" veremos algo como esto:
/usr/local/bin:/bin:/usr/bin:/usr/X11/bin:/home/sebas:/:.
Nótese que el ultimo exponente de la ruta es el directorio actual que habíamos indicado en el punto anterior sobre "ruta de búsqueda".
![]()
Como se puede observar cada uno de los directorios esta separado por ":" y en ultimo lugar esta la referencia al directorio actual que habíamos hablado anteriormente.
Otra variable muy importante es el "prompt" que no es ni más ni menos que la secuencia de caracteres que aparecen justo antes de lo que ingresamos en la interfase de comandos.
El entorno bash dispone de 4 prompt, "PS1", "PS2", "PS3" y "PS4". Estas variables tienen un porque. La denominación "PS1" es el prompt principal y es que vemos al iniciar el sistema. El "PS2" es el que aparece si al introducir algo que sobrepasa la línea y se va a la siguiente. Su valor por defecto es ">". Se puede comprobar ingresando el carácter "\" en la línea que estemos ingresando, con lo que pasaremos a la siguiente.
El "PS3" aparece cuando se utiliza el comando "select" de la interfase de comandos.
El "PS4" aparece cuando se efectúa el seguimiento de un comando.
El prompt y la mayoría de las variables de entorno pueden ser modificados con el comando "export". Con el podremos modificar el contenido de las variables, pero estas tendrán que nombrarse sin el signo "$".Ej:
[sebas@LUSI]$ export SECONDS=0
[sebas@LUSI]$ echo $SECONDS
0La variable $SECONDS cuenta la cantidad de segundos desde que entramos al sistema; con este mandato la setemos a "0". Existen variables que no pueden ser cambiadas, como UID, EUID o PPID, (se muestra un detalle de las variables mas útiles en la tabla 2.
Volviendo al prompt, este puede ser cambiado para que, por ejemplo, nos muestre el nombre de usuario seguido de una "@" y el nombre del sistema, con la ayuda de caracteres especiales.
[sebas@LUSI]$ export PS1='[\u@\h]\$'
Se muestra en la tabla 1 los caracteres especiales del prompt.
TABLA 2
Variable Definición PPID Numero de identificación del proceso padre de la interfaz de comandos. PWD Directorio de trabajo actual, establecido por el comando "cd". OLDPWD Anterior directorio de trabajo, establecido por el comando "cd". REPLY Cuando se usa el comando read de bash sin argumentos, esta variable recoge el contenido de la línea leída. UID Numero identificativo (ID) del usuario, establecida en el arranque del shell. EUID ID eficaz de usuario, inicializada en el arranque del shell. BASH Nombre completo, incluida la ruta, del archivo quese ejecuto para lanzar el shell. BASH_VERSIÓN Numero de versión de Bash. SHLVL Nivel del shell. Incrementa su valor en una unidad cada vez que se lanza una nueva interfaz de comandos. RANDOM Cada vez que se invoca a esta variable se obtiene un numero entero aleatorio. La secuencia de números aleatorios proporcionadas por RAMDOM se puede inicializar simplemente asignándole un nuevo valor a esta variable. SECONDS Mantiene el número de segundos que han transcurrido desde que se ejecuto el shell. Si asignamos un valor a esta variable, la cuenta indicara los segundos transcurridos desde dicha asignación, mas el valor asignado. LINENO Cuando se hace referencia a esta variable desde un script, indica la línea dentro del script en la que se le esta haciendo referencia, considerando que la primera línea se numera como 1. Si se invoca desde la propia interfaz de comandos, el valor que devuelve es él numero de línea que hace la orden ejecutada desde que se inicio la interfaz de comandos. HISTCMD Contiene la posición dentro del archivo de historia de comandos que ocupa el comando actual. HOSTTYPE Se trata de una cadena de texto describiendo el tipo de maquina en la que esta ejecutando el bash. HOSTNAME Nombre de la maquina. OSTYPE Se trata de una cadena de texto describiendo el sistema operativo en el que sé esta ejecutando el bash. PATH La ruta de búsqueda de comandos. Se trata de una secuencia de directorios en los que localizar los programas, separados entre si por un signo de dos puntos (:). La interfaz de comandos recorrerá esta lista en el orden dado buscando los comandos que queramos ejecutar. HOME Directorio raíz del usuario actual. Es el argumento usado por defecto cuando ejecutamos el comando "cd" sin especificar ninguno. CDPATH Se trata de la ruta de búsqueda para el cd. Tiene una estructura similar a la variable PATH. Lo que indica es donde se deben buscar los directorios especificados como argumentos al comando. Como ejemplo habitual, podría contener <<:~:/usr>>. ENV Contiene el nombre del fichero que define el entorno del shell en el que se ejecutan scripts. Algo asi como el archivo .bashrc para el shell cuando se inicializa, para lo relativa al entorno en que ejecuta un script. Cuando contiene el nombre de un archivo, bash comprueba en él la llegada de correo nuevo y avisa en caso que se produzca. MAILCHECK Determina el intervalo de tiempo en segundos que bash tomara para revisar si hay correos nuevos. MAILPATH Al igual que PATH y CDPATH, esta variable contiene una lista, en este caso, de archivos que deberán ser comprobados para la posible llegada de correo. Se puede indicar u mensaje especifico para la llegada de correo en diferentes buzones usando el carácter '?' como separador entre el archivo y el mensaje. En ese caso, la variable $_ obtendrá el nombre del buzón. Un ejemplo:MAILPATH='/var/spool/mail/nlucas?"Tienes correo":~/mail/buzon?"Ha llegado algo al $_"' PS1 Valor del prompt principal. En la tabla 1 se muestran los valores con los que puede expandirse. PS2 Valor del prompt secundario. Este prompt es el que aparece cuando partimos una línea en la interfaz de comandos para continuar introduciendo en la siguiente línea de la pantalla. PS3 Valor del tercer prompt. Este prompt es usado solamente por el comando select. PS4 Valor del cuarto prompt y ultimo. Tan solo se usa cuando se esta realizando un seguimiento de los comandos mostrándose para indicar los pasos por los que se va ejecutando el comando. Para entrar en el modo de seguimiento, basta con ejecutar set -x. Entonces veremos como cada comando que ejecutemos se expande, mostrando las sustituciones que se hacen con los alias, las variables, etc. HISTSIZE Contiene él numero de comandos a guardar en el historial de comandos. HISTFILE Contiene el nombre del archivo en el que se almacena el historial de comandos. Por defecto se trata del fichero ~/.bash_history. HISTFILESIZE Numero máximo de líneas que puede contener el archivo de historia. Tengamos en cuenta que un comando puede ocupar varias líneas. PROMPT_COMMAND Si esta definido, contiene el comando a ejecutar antes de presentar el prompt. IGNOREEOF Indica cuantas veces ha de recibir el carácter EOF (End Of File, o la pulsación de la tecla Crtl+D) antes de salir de bash. Si el valor indicado no es numérico, se toma por defecto el 10. Si no esta seleccionado, una única pulsación basta. TMOUT Si contiene un valor superior a cero, indica el número de segundos que se puede estar sin introducir un comando a el shell. Pasado este tiempo, la interfaz de comandos se cerrara. FCEDIT Ruta ynombre del editor usado por defecto para el comando fc. Por defecto se usa vi. FIGNORE Lista de subfijos de archivos que se ignoraran al intentar completar un nombre de archivo desde bash. La lista estará formada por los subfijos ignorados, separados por un signo de dos puntos (:). Por ejemplo <<.0:.tmp>> INPUTRC El nombre del archivo de arranque. Por defecto es ~/.inputrc. EDITOR En esta variable muchos programas buscaran la ruta y el nombre del editor a usar. Por defecto el editor usado es el vi. Algunos de los programas que hacen uso de esta variable son crontab (con la opción -e), edquota y otros muchos. TERM Contiene el tipo de terminal. Esta variable es importante, pues algunos tipos de terminales no son compatibles con algunos programas.
5.1.4 Expresiones regulares y uso de metacaracteres:
Empezaremos ampliando el uso de los comodines que antes mencionamos (* y ?). Es muy frecuente el uso de esta clase de caracteres para que el shell los expanda para que coincidan con cualquier carácter, en el caso de "?", y con cualquier cadena de caracteres, en el caso de "*".
La utilización de estos ya la definimos anteriormente y solo nos queda mostrar su utilización en función de las expresiones regulare.
La expresiones regulares son una serie de reglas que de cumplirse se expanden para poder ser utilizadas.
Para esto se utiliza también otro tipo de metacaracteres "[]" donde los caracteres que se introduzcan dentro serán reemplazados para completar el comando.
Supongamos que queremos editar con el programa vi los archivo carta.1 carta.2 carta.3 carta.4 y carta.5. Podríamos utilizar tanto el carácter ? como el * para editarlo. Pero también puede ser utilizado la serie de números del 1 al 5 encerrados dentro de los corchetes ([]).Ej Uso del carácter *
[sebas@LUSI]$ vi carta.*Con esto editaríamos todos los archivos desde carta.1 a carta.5.
Ej. Uso de la expresión regular.
[sebas@LUSI]$ vi carta.[12345]Con esta expresión, el interprete de comandos expandirá a cada uno de los caracteres encerrados entre los corchetes para que tome el lugar que corresponde en el nombre del archivo a editar.
¿Pero que pasaría si solo se quisiera editar el archivo carta.1, carta.2 y carta.5?
No podríamos utilizar ni el carácter "*" ni el "?" para hacerlo de un solo paso, pero si podremos usar la expresión regular de esta forma:[sebas@LUSI]$ vi carta.[12-5]
Con esto, y dado que el interprete de comandos solo interpreta de un carácter por vez, se editaran solamente los archivos carta.1, carta.2 y carta.5. Los numeros seran tomados dentro de los corchetes como caracters individuales.
La utilidad de las expresiones regulares es muy grande, y existen casos que es solamente con su utilización que puede realizarse un trabajo.
Las expresiones regulares podrán ser usadas, junto con otros comandos, también para identificar grupos de caracteres en un texto y representarlos según se pida.
Por ejemplo, utilizando el comando grep, que casualmente significa Global Regular Expresión Print, se podrá buscar dentro de un texto una cadena que se requiera y mostrarla por pantalla.
Supongamos que necesitamos mostrar todas las líneas que posean la palabra carta en el archivo documentos:[sebas@LUSI]$ grep carta documentos
Lo que nos devolverá las líneas que posean la palabra carta, aun aquellas que tengan entre sus letras un grupo de caracteres que sea igual al buscado, por ejemplo "cartas" o "pancarta".
Ahora bien, que pasaría si la palabra carta estuviese escrita con el primer carácter en mayúsculas. Entonces el comando grep no la mostraría, para esto podríamos usar una expresión regular de esta forma:[sebas@LUSI]$ grep [Cc]arta documentos
Si lo que necesitáramos es buscar las líneas que comiencen con la palabra carta, tanto con la "C" en mayúsculas o minúsculas usaríamos el símbolo circunflejo (^) y el comando seria este:
[sebas@LUSI]$ grep ^[Cc]arta documentos
Con esto indicaríamos que mostrara todas las líneas que tuviesen como primer palabra a "carta" tanto con la primera letra en mayúscula o minúscula.
Si lo que quisiéramos es mostrar todas las líneas de documentos que terminaran con la palabra "carta", tendríamos que usar la otra función que cumple el símbolo "$" (ya habíamos visto que hera usado para referenciar a una variable de entorno) que en las expresión regulare, y colocado al final de la expresión, indica que esta tendrá que ser buscada al final de la línea.
Primero le asignaremos la expresión a una variable para que el mandato sea más legible y se vea la utilización de las dos funciones del símbolo $:VAR=^[Cc]arta
[sebas@LUSI]$ grep $VAR$ documentos
Explicamos el uso de expresiones regulares solo con el comando grep, pero existe un sin numero de oportunidades para usarlas como los comandos en los cuales podrán también ser usadas. Se vera mas adelante que pueden ser muy utilizadas en el editor vi y nos harán muy fácil el trabajo con este.
5.1.5 Interpretación de Comandos
Hemos podido apreciar la utilización de una serie de comandos junto con aplicaciones comunes e estos, pero es de necesidad poder entender el método por el cual estos comandos son interpretados por el shell, para de esta manera tener un poco mas de entendimientos a la hora de elaborar nuestros propios script y programas.
Lo primero que se nos puede ocurrir averiguar, es el orden en que son interpretados los comandos.
Partiremos de la base que se pueden ejecutar mas de un comando en una linea; esto se logra separándolos con un punto y coma (;).Lo primero que el shell realiza es dividir estos comandos en lo que se denomina tokens. Cada token es un comando, junto con
sus argumentos, a ejecutar.
Una vez que el shell puede saber cuantos tokens hay, determina su sintaxis. Si existe un error en este punto, ninguno de los tokens se ejecutara y el shell nos advertirá de un posible error de sintaxis.
Si la sintaxis es correcta, comienza la interpretación de los comandos.
A partir de aquí el shell trata de ver si alguno de los tokens es en realidad una funcion del propio shell. Si existe esta sera expandida antes de ser ejecutada.
Luego, se expanden los alias . Si alguno de os tokens es en realidad un alias, ya sea creado por el usuario o no, este se expandirá antes de ejecutarse. Si el alias llama a otro alias, este también se expandirá antes de ejecutarse.
Una vez que se han expandido los alias y funciones el shell comenzara a evaluar las variables y las sustituirá con su valor.
Al terminar esto, se expandirá cualquier comodín utilizado expandiéndolo al nombre de archivo o comando que concuerde de acuerdo a las reglas antedichas.
Ahora, aunque esta la mayor parte del comando evaluado, el shell tendrá todavía que ver si el primero de los tokens corresponde a un comando del shell o a un programa externo. Si esto ocurriera, se tendrá que consultar la ruta de búsqueda.
Vera luego si existe algún tipo de redirección o canalización, tema que veremos mas en detalle en el próximo capitulo, por el cual la entrada o salida de un comando este redirigida a otro lugar.
Una vez que se a podido analizar todo el comando o conjunto de comandos a su mínima expresión, conjunto de datos binarios, el shell efectuara una copia de si mismo, a través de la llamada a sistema fork() para poder ejecutar el script. Esta copia es un hijo del shell y que depende del shell que lo origino.
Luego de esto, el shell hijo, usara una llamada a sistema denominada exec() para poder ejecutar el binario correspondiente.
Aunque quien lo ejecuta es en realidad el shell hijo, hay que recordar que el padre todavía se encuentra en memoria esperando la finalización del proceso hijo.
Puede darse el caso que se desee que quien ejecute el comando o script sea el propio shell y no un shell -hijo, eso se logra con la utilización del comando "." punto.
Al anteponer un punto al comando o script y dejando un espacio entre ellos, el shell entenderá que es el mismo quien debe interpretar este comando o script.Ej.
[sebas@LUSI]$ . myscript
Este script será interpretado sin que se genere un sub-shell hijo.
Esta es una simplificación de la ejecución de un comando tipo, no quiere ser una explicación total de lo que puede ocurrir dado la gran cantidad de variantes que intervienen, pero servirá como base de entendimiento de lo que el shell realiza una vez que se ha presionado la tecla "ENTER".
5.2 Funciones
Uno de las mayores utilidades que posee una shell es el permitirnos crear funciones para realizar tareas repetitivas fácilmente.
El funcionamiento de estas funciones es parecido al que posee cualquier lenguaje de programación, en el cual se agrupan conjunto de comandos y se los llama por un nombre.
El formato de las funciones es el siguiente:
nombre_funcion()
{
primero_a_realizar
segundo_a_realizar
}
Estas fusiones pueden ser definidas en cualquier lugar, incluso en la misma línea de comandos. Lo que habrá que recordar que hechas de esta forma se borraran de la memoria una vez que se a salido del shell.
Una forma es incorporarla en el archivo de inicio del shell, el .bash_profile, en el cual se pondrá la función. De esta forma podremos seguir utilizándola dado que será cargada en memoria cada vez que ejecute el shell.
Un ejemplo de una función simple seria:que_tal()
{
echo Hola $1 como estas?
}[sebas@LUSI]$ que_tal Sebastián
Hola Sebastián como estas?
Aquí podemos ver dos factores en la creación de funciones.
Primero que todo se nombre a la función y se emplean un par de paréntesis "( )" con lo cual se indica al shell que lo que viene a continuación deberá ser tomado como una función.
Inmediatamente después de los paréntesis se abrirá una llave "{", con lo que se indica que comienzan los comandos de la función. Al terminar se cierra la llave "}".
El otro punto es el reemplazo que efectúa el shell de las variables. Aquí la variable se asigna directamente y es un numero que vendrá después del signo "$". Este numero indica el numero del argumento de que tomara su valor y que es dado al invocar a la función. En este caso su valor pasa a ser "Sebastián". Podremos asignar más variables de este tipo que serán tomadas de acuerdo a su valor numérico como el numero del argumento.Ej:
que_tal()
{
echo Hola $1 como estas?
echo Espero que estés $2
}
[sebas@LUSI]$ que_tal Sebastián bienHola Sebastián como estas?
Espero que estés bienComo en la programación, donde los limites entre las funciones y los procedimientos esta dada de acuerdo a la función que se esta cumpliendo, en el caso de las funciones del shell varia de acuerdo donde se encuentre guardada.
Una función esta en memoria y puede ser cargada por el shell a partir de un archivo como el .bash_profile que es leído por él al iniciarse.
En caso de que se creara un archivo aparte con permisos de ejecución, esta función pasaría a ser un script pero se necesitaría que se llame a la función desde dentro del mismo script. Volveremos a esto al tratar el tema de script de shell pero daremos un ejemplo para que se entienda mejor.
Supongamos que creamos un archivo llamado saludo.sh y le damos permisos de ejecución con el comando chmod:
El signo # representa un comentario
cat > saludo.sh #Con el comando "cat" y redirigiendo su
#salida se puede crear un archivo
que_tal() #a continuación se ingresa la función
{
echo Hola $1 como estas?
echo Espero que estés $2
}
que_tal $1 $2 #Ahora la función es llamada desde dentro #del script. #Al finalizar se presionanlas teclas ctrl+D[sebas@LUSI]$ chmod +x saludo.sh #Le damos los permisos de #ejecución solo para #nosotros
[sebas@LUSI]$ ./saludo.sh Sebastián bien
Lo ejecutamos, dado que estamos parados en el mismo directorio en que lo creamos, anteponemos un punto y la barra para que el shell sepa que nos estamos refiriendo al directorio actual. El resultado es:
Hola Sebastián como estas?
Espero que estés bien5.3 Características adicionales:
Depuración de Script:
Es posible depurar u script si se escribe set -x antes de ejecutarlo. De esta forma cada comando se mostrara en pantalla antes de ejecutarse con su correspondientes argumentos.
Se desactiva ingresando set +x.
Si lo que se quiere es mandar la salida a un archivo se tendrá que tener en cuenta que la salida del "set -x" no va hacia la salida estándar "stdout" sino hacia el error estándar "stderr".
Si tomamos que la entrada estándar (stdin) es el "0", la salida estándar (stdout) es el "1", entonces el tercer archivo (sterr) es el "2".
Por ello si se quiere depurar el script myscript y mandar la salida a un archivos, se tendrá que ingresar los siguiente luego del "set -x":[sebas@LUSI]$ myscript 2>archivo_salida
Esto indica que se deve mandar el descriptor de archivo 2 (stderr) al archivo "archivo_salida".
Creación de directorios múltiples:
Supongamos que queremos crear un subdirectorio en el directorio /home/sebas/cartas/trabajo/mensuales, pero ni el directorio /cartas ni /trabajo están creados aún.
A través del modificador -p del comando mkdir de esta forma parados sobre el directorio /home/sebas:[sebas@LUSI /home/sebas]$ mkdir -p /cartas/trabajo/mensuales
De esta forma primero se creara el directorio /cartas, luego /trabajo y por ultimo /mensuales.
Sebastián D. Criado -
www.lugro.org.ar
seba_AT_lugro.org.ar