CAPITULO IV Shell y comandos 1 La Shell Todo S.O. debe proveer un mecanismo para que el/los usuarios puedan comunicarle lo que quieren realizar y para poder interactuar con el. Linux posee una interfase de comunicación llamada "shell" y es el medio mediante el cual el usuario puede comunicarle comandos al sistema y recibir la salida de los procesos con los que interactúa. Básicamente, la shell es un proceso mas que obviamente se ejecuta en primer plano, ya que sino seria imposible interactuar con el mismo. Su funcionamiento se limita a recibir comandos del usuario, interpretarlos y ejecutar las tareas necesarias en respuesta a los mismos. El nombre técnico de la shell puede ser "interprete de comandos". Su función se puede comparar a la del programa "comand.com" en MS-DOS que esencialmente realiza las mismas tareas. En los sistemas UNIX cada usuario puede elegir que shell quiere utilizar para comunicarse con el sistema. Linux tiene varias shells las cuales pueden ser elegidas por el usuario. Inclusive es posible que el usuario programe y utilice su propia shell si así lo desea. Las shells que Linux provee son: 9 sh: Shell de Bourne. Es la shell mas utilizada en los sistemas UNIX. 9 csh: Shell de C. Es la shell preferida por los programadores. Es compatible con la shell _______de Bourne. 9 ash: Shell de Ash. Es una versión especial reducida. Se utiliza cuando existe muy poca _______memoria disponible. 9 ksh - pdksh: Shell de Korn. Extensión de la shell de Bourne. 9 bash: Bourne Again Shell. Es la shell de la FSF (Free Software Fundation). Amplia las _______capacidades de la shell de Bourne y es utilizada por Linux como shell _______predeterminada. 9 zsh: Z Shell. Compatible con la shell de Bourne. Funcionamiento de la Shell La shell es iniciada inmediatamente cuando un periodo de inicio de sesión es autenticado exitosamente. El sistema recuerda cual es la shell que utiliza cada usuario y carga la correspondiente al usuario que inicio la sesión. Desde este momento, la shell muestra un identificador llamado "prompt" que significa que esta esperando que el usuario ingrese una orden. Una vez que se visualiza el prompt, el usuario puede ingresar cualquier orden, ya sea para que se ejecute en primer plano o en "background". Si el pedido de ejecución dado por el comando ingresado especifica que el proceso se debe ejecutar en "background", el proceso se inicia y se comienza a ejecutar en "background", por lo que el shell inmediatamente vuelve a mostrar el prompt y al estado de espera de mas ordenes. Así es posible seguir ejecutando órdenes. Si el proceso se debía ejecutar en primer plano, la shell no retorna el prompt hasta que el proceso 2 ejecutado se termine. Por lo tanto debemos esperar a que termine el proceso para poder iniciar otro. Comandos NOTA: Desde esta sección en adelante todo lo referente a la shell y sus comandos estará basado en la shell bash (Bourne Again Shell) que es la shell predefinida en Linux :) El uso interactivo típico de la shell se basa en ingresar comandos simples, comandos con calificadores, comandos con facilidades de generación de nombres de archivos, redirección de entrada-salida, y comandos combinados mediante el uso de "cañerías". Estas técnicas son poderosas y extremadamente útiles, pero son solo una parte de las capacidades de la shell. La shell es, además de intérprete interactivo de comandos, un intérprete de un lenguaje de programación de comandos llamado "El lenguaje de programación de la shell". Este lenguaje nos permite realizar nos permite realizar "scripts" que será posible ejecutar como un programa binario mas, con la diferencia que lo interpreta la shell línea por línea y ejecuta los comandos correspondientes. Más adelante nos ocuparemos de analizar este lenguaje de programación en profundidad, ya que es una de las características más poderosas de la shell y nos sirve para automatizar muchas de las tareas que tenemos que realizar en el sistema y nos ayuda a ahorrar la cantidad de comandos que tenemos que tipear. Comandos Simples Un comando simple es una secuencia de (una o más) palabras separadas por espacios o tabuladores. La primera palabra de la secuencia es el nombre del comando. Las palabras subsiguientes son los argumentos del comando. Los comandos más simples son de una sola palabra. Los comandos más comunes pueden ser: ls para listar el contenido de un directorio, ps para ver los procesos que se encuentran creados en el sistema, reboot para reiniciar el sistema, etc. 3 Argumentos Los comandos, en su forma más simple, se ejecutan simplemente poniendo el nombre del archivo correspondiente. Sin embrago, existen comandos que necesitan argumentos para trabajar. Un ejemplo de esto puede ser el comando cp que sirve para copiar archivos. Este comando necesita dos argumentos obligatorios, el/los archivo fuente y el destino de la copia. Por ejemplo: ==> cp /home/juan/cuotas.tex /home/tony/ Los argumentos se utilizan para pasar información adicional a los programas que ejecutamos. En algunos casos son opcionales, en otros obligatorios y puede ser que la cantidad de argumentos de algunos comandos pueda ser variable. La gran mayoría de las veces los argumentos serán nombres de archivos o de directorios, pero esto es dependiente de cada programa. El nombre del comando y sus argumentos deben ser separados por uno o mas espacios, sino la shell nos informara del error con un mensaje. Ejemplo: ==> ls/bin bash: ls/bin: No such file or directory Otros argumentos son los "modificadores" que son formas de pasar opciones a los programas y serán tratados a continuación. Modificadores Los comandos, usualmente, sirven para realizar una función pero pueden aceptar varias opciones que especifiquen como se debe realizar esta tarea. Las opciones que cada comando acepta y la sintaxis con la que se especifica la opción dependen exclusivamente del comando en cuestión. Aunque en general se puede hablar de "modificadores" que son la forma general de ingresar las Opciones a los comandos. Consideremos el siguiente comando: ==> ls -a Este comando listara el contenido del directorio actual, pero mostrara además los que comienzan con ".", ya que estos son ocultos y al ejecutar ls no son mostrados. Este comportamiento es especificado por la opción de mostrar los archivos ocultos que es seleccionada con el modificador a (all). NOTA: Un modificador muy útil es -h que sirve para especificarle a un comando que nos muestre su sintaxis y las opciones que soporta. Esto sirve como referencia del funcionamiento del comando. Este modificador se puede usar con la mayoría de los comandos de Linux. Algunos comandos soportan --help o -help para la misma función. 4 Separador de Comandos Para ingresar varios comandos en una sola linea es necesario separarlos por ";". Por ejemplo: ==> date;df -h La salida de este comando sera la siguiente: Thu Apr 15 17:29:15 ART 2004 Filesystem Size Used /dev/hda3 1.6G 613M /dev/hdc1 2.0G 1.9G /dev/hda2 298M 238M /dev/hda1 2.0G 1.5G Avail 963M 138M 60M 546M Capacity 39% 93% 80% 73% Mounted on / /akenaton /games /nt La primera línea de la salida es generada por el comando date y muestra la hora y el día actual en el sistema. La tabla que es mostrada a continuación es generada por el comando df y muestra las capacidades, tamaños utilizados y disponibles, y puntos de montaje de los distintos sistemas de archivos que se encuentran montados. Notemos que las unidades se muestran en distintos formatos de acuerdo al valor que tenga cada campo. Esto es causado por la opción -h que indica al comando que muestre los valores con unidades significativas y no en numero de bloques. La entrada estándar y la salida estándar Los programas basados en el modelo de entrada/salida por teletipo son aquellos en los que su salida consiste en líneas de texto ASCII. Estos programas ofrecen solo una primitiva interfase con el usuario basada en línea de comandos. Pero justamente por esto, y por la funcionalidad que provee la shell, es posible interconectar varios programas que realizan tareas simples para realizar tareas mas complejas. Todos los comandos de Linux y la mayoría de sus utilidades se encuentran basados en este modelo. Por esto es importante entender el funcionamiento e interacción de los programas, la shell y la entrada/salida para sacar provecho a estas facilidades. Cuando un programa, del modelo de teletipo, produce una salida sobre una Terminal el programa, en general, esta realizando operaciones de salida a lo que se denomina salida estándar (stdout). Asimismo, cuando tipeamos algo en el teclado de la Terminal, un programa lee los caracteres de lo que se llama entrada estándar (stdin). Para comunicar errores y mensajes de diagnostico, existe una conexión de salida separada llamada stderr. 5 La shell, por ejemplo, es un programa que lee caracteres de stdin e interpreta los mismos como comandos, argumentos, etc. El comando ls envía su salida (el contenido del directorio de trabajo) a stdout y luego se visualiza en nuestra pantalla. Este funcionamiento es el predefinido, ya que la entrada estándar y la salida estándar se encuentran, normalmente, asociadas a la terminal de la computadora, stdin el teclado y stdout a la pantalla. La shell, sin embargo, nos permite reasignar o redireccionar las conexiones de entrada, salida o la de diagnostico de errores. Esta es una de las características mas poderosas de Linux :) Redireccionando la Salida Supongamos que ejecutamos el comando ps (process status), el cual nos reporta del estado de los procesos, que nosotros iniciamos, que se están ejecutando en el sistema. La figura nos muestra la salida generada por una ejecución del comando ps. Así visualizamos la salida en nuestra pantalla. # ps PID TTY STAT 338 1 S 356 1 S 368 1 S 372 1 S 373 1 S 377 1 S 381 1 S 394 1 S 412 p0 S 415 1 S 479 1 S 515 p0 R TIME COMMAND 0:00 /bin/login -- root 0:00 -bash 0:00 sh /usr/X11R6/bin/startx 0:01 wmaker 0:06 kfm 0:00 wmmon 0:00 mount.app 0:37 emacs 0:01 kdvi apunte.dvi 0:01 /usr/local/bin/x11amp 0:00 kvt 0:00 ps Ejecucion del comando ps Si nos interesa guardar la salida del comando ps, por ejemplo para analizarla posteriormente, podemos hacer uso de la redirección de la salida que nos brinda la shell. Le indicamos a la shell que queremos redireccionar la salida con el símbolo ">". Entonces, en nuestro ejemplo, debemos ejecutar el comando como indica la figura. En la misma, observamos que el comando termina de ejecutarse sin realizar ninguna salida en la pantalla, pues la salida del comando se envió al archivo "procesos" y fue guardada en el mismo. Luego mostramos el contenido del archivo procesos, con el comando cat, y visualizamos la salida que el comando ps realizo al ejecutarse. 6 # ps > procesos # cat procesos PID TTY STAT TIME COMMAND 338 1 S 0:00 /bin/login -- root 356 1 S 0:00 -bash 368 1 S 0:00 sh /usr/X11R6/bin/startx 372 1 S 0:01 wmaker 373 1 S 0:06 kfm 377 1 S 0:00 wmmon 381 1 S 0:00 mount.app 394 1 S 0:37 emacs 412 p0 S 0:01 kdvi apunte.dvi 415 1 S 0:01 /usr/local/bin/x11amp 479 1 S 0:00 kvt 515 p0 R 0:00 ps b. Ejecución del comando ps redireccionando la salida al archivo "procesos" NOTA: No es necesario que el archivo sobre el cual escribimos al redireccionar la salida exista antes de ejecutar el comando ya que la shell crea el archivo, si es necesario. Redirección no-destructiva de la Salida Al redireccionar la salida de un comando a un archivo se sobrescribe completamente los contenidos del mismo. Hay ocasiones en las que no queremos perder la información almacenada en un archivo, sino agregarle datos al final del mismo. En el ejemplo de la figura anterior, los contenidos del archivo procesos, si existían antes de ejecutarse el comando, son sobrescritos. Para poder concatenar información en un archivo usamos ">>" en vez de ">". Redireccionando la conexión de errores estándar La conexión de errores estándar es la segunda conexión de salida que el S.O. Linux abre para cada programa. Normalmente es conectada a la Terminal, o sea a nuestra pantalla, y es por eso que cada vez que un programa muestra un mensaje de error, este es visualizado en ella. Si ejecutamos un comando y redireccionamos la salida del mismo a un archivo, no estamos cambiando para nada la conexión de errores estándar de ese comando, por lo que cualquier mensaje de error que el comando reporte será visualizado en pantalla. Esto ocurre porque la conexión de errores estándar no se encuentra redireccionada. Hay programas que producen una cantidad voluminosa de salida. En estos casos uno puede querer redireccionar la conexión de errores estándar a un archivo, para luego examinar los mensajes que el programa genero. Para redireccionar la conexión de errores estándar se utiliza "2>". El numero 2 indica el numero de conexión de salida que es justamente la conexión de errores estándar. 7 Redireccionando la entrada También es posible redireccionar la entrada. Ya vimos que uno de los programas que lee la información de la entrada es la shell, los demás programas que vimos (ls, ps, cat, etc.) producen su salida sin leer de la entrada estándar. La shell lee los comandos a ejecutar de la entrada Standard. Como la entrada estándar puede ser redireccionada a un archivo, es posible que la shell obtenga los comandos a ejecutar desde un archivo. Un ejemplo de esta situación se muestra en la figura 6.2. En la misma vemos que los contenidos del archivo "comandos" son los nombres de dos comandos de Linux: date y ps. Luego utilizando el símbolo "<" redireccionamos la entrada del programa bash (Bourne Again Shell) al archivo comandos y los resultados se muestran en pantalla. Redireccionando la salida y la entrada simultáneamente Es posible redireccionar, simultáneamente, la entrada estándar y la salida estándar. Cuando esto sucede, el único rol que cumple la Terminal es ingresar el comando que vamos a ejecutar, pero luego el programa trabaja sin tener asociada la entrada ni la salida a la Terminal. Salvo que no se redireccione la conexión de errores estándar porque los mensajes de error serian visualizados en pantalla. La forma de redireccionar la salida y la entrada simultáneamente se muestra con un ejemplo en la figura 6.3. Cañerías: la interconexión entre programas Las cañerías (pipes) conectan la salida estándar de un programa con la entrada estándar de otro programa. Una cañería es diferente a la redirección de la entrada/salida. Al redireccionar la entrada conectamos la entrada de un programa a un archivo y al redireccionar la salida conectamos la salida del programa a un archivo. Una cañería conecta la salida de un programa directamente con la entrada de otro programa. Ver figura 6.4. Para construir una cañería debemos separar los comandos que queremos conectar con el símbolo "|". En el ejemplo de la figura 6.5, conectamos dos comandos: ls y wc. El primero nos lista el contenido de un directorio, en este caso del directorio /bin. El segundo comando, wc (word count) sirve para contar palabras, líneas y caracteres, pero al pasarle la opción -w le estamos diciendo que solo cuente palabras. El funcionamiento de este pipe es muy simple: El comando ls lee el contenido del directorio /bin y genera una lista de palabras con los nombres de los archivos y 8 directorios encontrados. Esta lista, en vez de ser enviada a la Terminal, es redireccionada a la entrada estándar del comando wc que comienza a contar las palabras y muestra el resultado en la salida estándar del mismo que es la Terminal. Generación de nombres de archivos El S.O. Linux nos permite especificar conjuntos de nombres de archivos automáticamente utilizando "generación de nombres de archivos y caracteres comodines". Cuando ingresamos argumentos a un comando, la shell examina los mismos con el objeto de detectar el uso de la generación de nombres de archivos. El usuario controla la generación de nombres de archivos especificando un modelo para los nombres de archivo. La shell compara el modelo provisto con todos los archivos del directorio de trabajo. Si alguno de los nombres de archivo responde al modelo, entonces una lista ordenada alfabéticamente con todos los nombres de archivos que responden al modelo es enviada al programa. Si ninguno de los nombres de archivo del directorio actual cumple con el modelo, entonces el modelo (en forma textual) es enviado al programa como argumento. Un modelo consiste de caracteres ordinarios y de "metacaracteres" llamados caracteres comodines. Los caracteres ordinarios son interpretados textualmente; los metacaracteres tiene un significado propio. Los metacaracteres utilizados para la generación de nombres de archivo y sus significados se muestran en la tabla 6.1. |øøøøøøøøøøøøøø|øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø| | Metacaracter | Significado | |--------------|----------------------------------------------------------| | * | Equivale a cualquier cadena de caracteres | | ? | Equivale a cualquier caracter | | [ | Comienza una clase de caracteres | | ] | Termina una clase de caracteres | | | Indica un rango de caracteres en una clase de caracteres | |______________|__________________________________________________________| Tabla 6.1: Metacaracteres utilizados para generacion de nombres de archivo. El asterisco y el signo de pregunta son muy fáciles de usar. Por ejemplo *.c equivale a todos los archivos que tienen como sufijo .c como pueden ser: prog.c, ab.c, Main.c; los siguientes nombres no satisfacen el modelo unit2.cc, main.c.cc; el modelo ???.tex equivale a todos los nombres de archivo que tengan tres caracteres cualesquiera y luego el sufijo .tex, Por ejemplo: ref.tex, cp1.tex, bea.tex, c++.tex, cumplen con el modelo pero ab.tex, tony.tex, intro.tex chapter1.tex.z no lo satisfacen. 9 Los corchetes y el signo menos se utilizan para formar modelos para grupos de caracteres. Los caracteres en el grupo (o clase) son especificados dentro de los corchetes. El modelo abc[aeiou] representa todo nombre de archivo que comience con abc y culmine con una única vocal. El signo menos se utiliza para especificar rangos de caracteres. El modelo chapter[0-9] representa a todos los nombres de archivo que comienzan con chapter y finalizan con un digito. Notemos que el rango incluye a sus límites. Es necesario realizar una aclaración con respecto a los archivos ocultos. Recordemos que todo archivo tal que su nombre comience con un punto es considerado un archivo oculto. La generación de nombres de archivos no considerara que un modelo representa a un archivo oculto si no se especifica explícitamente el punto al comienzo del modelo. Por ejemplo: El modelo xinit* no representara al archivo cuyo nombre es .xinitrc. Para solucionar esto es necesario especificar el modelo de la siguiente forma .xinit*. # ps PID TTY STAT 338 1 S 356 1 S 368 1 S 372 1 S 373 1 S 377 1 S 381 1 S 394 1 S 412 p0 S 415 1 S 479 1 S 515 p0 R TIME COMMAND 0:00 /bin/login -- root 0:00 -bash 0:00 sh /usr/X11R6/bin/startx 0:01 wmaker 0:06 kfm 0:00 wmmon 0:00 mount.app 0:37 emacs 0:01 kdvi apunte.dvi 0:01 /usr/local/bin/x11amp 0:00 kvt 0:00 ps a. Ejecucion del comando ps # ps > procesos # cat procesos PID TTY STAT TIME COMMAND 338 1 S 0:00 /bin/login -- root 356 1 S 0:00 -bash 368 1 S 0:00 sh /usr/X11R6/bin/startx 372 1 S 0:01 wmaker 373 1 S 0:06 kfm 377 1 S 0:00 wmmon 381 1 S 0:00 mount.app 394 1 S 0:37 emacs 412 p0 S 0:01 kdvi apunte.dvi 415 1 S 0:01 /usr/local/bin/x11amp 479 1 S 0:00 kvt 515 p0 R 0:00 ps b. Ejecucion del comando ps redireccionando la salida al archivo "procesos" Figura 6.1: Redireccionando la salida del comando ps. 10 # cat comandos date ps # bash < comandos Thu Apr 15 19:47:03 ART 1999 PID TTY STAT TIME COMMAND 338 1 S 0:00 /bin/login -- root 356 1 S 0:00 -bash 368 1 S 0:00 sh /usr/X11R6/bin/startx 372 1 S 0:01 wmaker 373 1 S 0:06 kfm 377 1 S 0:00 wmmon 381 1 S 0:00 mount.app 394 1 S 0:37 emacs 412 p0 S 0:01 kdvi apunte.dvi 415 1 S 0:01 /usr/local/bin/x11amp 479 1 S 0:00 kvt 515 p0 R 0:00 ps Figura 6.2: Redireccionando la entrada para que la shell ejecute comandos desde un archivo. # cat comandos date pwd # bash < comandos > salida # cat salida Thu Apr 15 20:06:30 ART 1999 /home/tony/docs/linux Figura 6.3: Redireccionando la entrada y la salida. |øøøø|__ <------------------------------------------------------\ |---|____| |_____ | | | | | stderr | | |______| | -----------------------------------> |øøøøøøøø| | | | | | | | |---------| | _--> |________| | | PROG1 | | | | | |______________| --\ | /øøøøøøøøø\ --/ | stdout | øøøøøøøøøøøøø | | | | | | \ | | | |øøøø|__ | | |---|____| |_____ | | | | | | <--/ stdin | | |______| | | | | | | |---------| | stdout & stderr | | PROG2 | | |______________| -----------------------------/ Figura 6.4: Ca¤eria de dos programas. # ls /bin | wc -w 75 Figura 6.5: Ejemplo de una ca¤eria. Contar la acntidad de archivos en un directorio. 11