Unix es un potente sistema para aquellos que saben cómo dominar su poder. En este capítulo, intentaré describir varias maneras de usar el shell de Unix, bash, más eficientemente.
Comodines
En el capítulo anterior, se enseñaron los comandos para mantener ficheros cp, mv, y rm. A veces, se querrá tratar con más de un fichero a la vez, en realidad, con muchos a la vez. Por ejemplo, se quiere copiar todos los ficheros que empiecen por data en un directorio llamado /backup. Se podría hacer esto ejecutando muchos comandos cp, o escribiendo cada fichero en una línea de comando. Estos dos métodos llevan mucho tiempo, incluso, se tienen muchas posibilidades de cometer errores.
Una buena manera de hacer este trabajo es teclear:
/home/larry/report$ ls -F
1993-1 1994-1 data1 data5
1993-2 data-new data2
/home/larry/report$ mkdir ~/backup
/home/larry/report$ cp data* ~/backup
/home/larry/report$ ls -F ~/backup
data-new data1 data2 data5
/home/larry/report$
Como se puede observar, el asterisco indica a cp que tome todos los ficheros que empiecen por data y los copie a /backup. ¿Qué cree que "cp d*w /backup" puede haber hecho?
¿Qué ocurre realmente?
Buena pregunta. De hecho, hay un par de caracteres especiales interceptados por el shell, bash. El carácter "*" , un asterisco, dice "cambia esta palabra con todos los ficheros que se ajusten a esta especificación". Así, el comando "cp data* /backup" , como el de arriba, cambia a "cp data-new data1 data2 data5 /backup" antes de ejecutarse.
Para ilustrar esto, introduciré un comando nuevo, echo. echo es un comando extremadamente simple; repite, o muestra, cualquier parámetro. De este modo:
/home/larry$ echo Hola!
Hola!
/home/larry$ echo Como se encuentra?
Como se encuentra?
/home/larry$ cd report
/home/larry/report$ ls -F
1993-1 1994-1 data1 data5
1993-2 data-new data2
/home/larry/report$ echo 199*
1993-1 1993-2 1994-1
/home/larry/report$ echo *4*
1994-1
/home/larry/report$ echo *2*
1993-2 data2
/home/larry/report$
Como se puede ver, el shell expande el comodín y pasa todos los ficheros al programa que se va a ejecutar. Esto plantea una pregunta interesante: ¿qué ocurre si no hay ficheros que se ajusten a la especificación del comodín? Pruebe "echo /rc/fr*og" y bash pasará literalmente la especificación del comodín al programa.
Otros shells, como tcsh, en vez de pasar el comodín literalmente, contestarán No match. Aquí está el mismo comando ejecutado bajo tcsh:
mousehouse>echo /rc/fr*og
echo: No match.
mousehouse>
La última pregunta que podría hacerse es, ¿qué pasa si quisiera mostrar data*, en vez de la lista de nombres? Bien, tanto en bash como en tcsh, sólo se debe incluir la cadena entre comillas:
/home/larry/report$ echo "data*" mousehouse>echo "data*"
data* Ó bien data*
/home/larry/report$ mousehouse>
El signo de interrogación
Además del asterisco, el shell también interpreta un signo de interrogación como un carácter especial.
Un signo de interrogación coincidirá con un carácter, y sólo uno. Por ejemplo, "ls /etc/*
*??" mostrará todos los ficheros de dos letras en el directorio /etc.
Ganar tiempo con bash
Editando la línea de comandos
A veces, escribe un comando largo a bash y, antes de pulsar |_Intro_|, se da cuenta de que ha cometido un error al escribirlo. Se puede simplemente borrar todo y volver a teclear correctamente, pero ¡es demasiado esfuerzo! En cambio, se pueden usar las flechas para moverse, borrar el/los carácter/es incorrecto/s, y escribir la información correctamente.
Hay muchas teclas especiales que ayudan a editar la línea de comandos, muchas de ellas similares a los comandos usados en GNU Emacs. Por ejemplo, |_C-t_| intercambia dos carácteres adyacentes1.
Se pueden encontrar muchos de los comandos en el capítulo sobre Emacs, Capítulo 8.
Completamiento de comandos y nombres de fichero
Otra peculiaridad de bash es la ejecución automática de las líneas de comando. Por ejemplo, veamos el siguiente ejemplo de un comando cp típico:
/home/larry$ ls -F
esto-es-un-fichero-largo
/home/larry$ cp esto-es-un-fichero-largo corto
/home/larry$ ls -F
corto esto-es-un-fichero-largo
/home/larry$
Es una gran molestia tener que teclear cada letra de esto-es-un-fichero-largo cada vez que se quiere acceder a él, sucede lo mismo si queremos crear esto-es-un-fichero-largo copiando en él /etc/passwd2. Ahora, aprenderemos a escribir el anterior comando cp más rápidamente y con menos posibilidad de error.
En vez de teclear el nombre del fichero entero, se escribe "cp es" , se pulsa y suelta la tecla |_Tab_|. Por arte de magia, el resto del nombre del fichero aparece en la línea de comandos, y se puede escribir corto. Desgraciadamente, bash no pude leer los pensamientos, por lo que se debe teclear corto.
Cuando se pulsa |_Tab_|, bash mira lo que hay escrito y busca un fichero que empiece como eso. Por ejemplo, si tecleo /usr/bin/ema y luego pulso |_Tab_|, bash encontrará /usr/bin/emacs ya que es el único fichero que empieza por /usr/bin/ema en mi sistema. En cambio, si tecleo /usr/bin/ld y pulso |_Tab_|, bash me avisará. Eso es porque tres ficheros, /usr/bin/ld, /usr/bin/ldd, y /usr/bin/ld86 empiezan por /usr/bin/ld en mi sistema.
Si se intenta un completamiento y bash avisa, se puede pulsar inmediatamente |_Tab_| otra vez para conseguir una lista de todos los ficheros que coincidan con el patrón. De este modo, si no se está seguro del nombre exacto del fichero, podemos teclear los primeros caracteres del nombre y buscarlo en una lista más pequeña de ficheros.
La entrada estándar y La salida estándar
Intentemos abordar un problema simple: conseguir un listado del directorio /usr/bin. Si hacemos "ls /usr/bin" , algunos de los nombres de los ficheros saldrán por arriba de la pantalla. ¿Como se pueden ver todos los ficheros?
Algunos conceptos de Unix
El sistema operativo Unix facilita mucho a los programas el uso del terminal. Cuando un programa escribe algo en la pantalla, está usando algo llamado salida estándar. Salida estándar, en inglés standard output o stdout, es la manera que tiene el programa de escribirle cosas al usuario. El nombre por el que se indica un programa es entrada estándar (stdin). Es posible que un programa se comunique con el usuario sin usar la entrada o salida estándar, pero la mayoría de los comandos que se tratan en este libro usan stdin y stdout.
Por ejemplo, el comando ls imprime una lista de los directorios en la salida estándar, que está normalmente "conectada" al terminal. Un comando interactivo, como el shell, bash, lee los comandos de la entrada estándar.
Un programa también puede escribir en el error estándar, ya que es muy fácil hacer que la salida estándar apunte a cualquier lugar aparte del terminal. El error estándar (stderr) está casi siempre conectado al terminal para que alguna persona pueda leer el mensaje.
En esta sección, examinaremos tres modos de enredarse con la entrada y salida estándar: redireccionar la salida, redireccionar la entrada, y las tuberías.
Redireccionar la salida
Un aspecto muy importante de Unix es la posibilidad de redireccionar la salida. Esto permite que, en vez de ver los resultados de un comando, los salvemos en un fichero o los enviemos directamente a una impresora. Por ejemplo, para redireccionar la salida del comando "ls /usr/bin", se coloca un signo ">" al final de la línea, y se indica el fichero donde dejar la salida:
/home/larry$ ls
/home/larry$ ls -F /usr/bin > listado
/home/larry$ ls
listado
/home/larry$
Como se puede ver, en vez de escribir los nombres de todos los ficheros, el comando crea un fichero totalmente nuevo en el directorio actual. Echemos un vistazo a este fichero usando el comando cat.
Si se recuerda, cat era un comando bastante inútil que copiaba lo que se escribía (entrada estándar) al terminal (salida estándar). cat también imprime un fichero en la salida estándar si se indica el fichero como parámetro:
/home/larry$ cat listado
..
/home/larry$
La salida exacta del comando "ls /usr/bin" aparece en el contenido de listado. Por ahora todo bien, sin embargo no resuelve el problema original.3
A pesar de todo, cat hace algunas cosas interesantes cuando se redirecciona su salida. ¿Qué hace el comando "cat listado > fichero"? Normalmente, el "> fichero" dice "coge toda la salida del comando y ponla en fichero". La salida del comando "cat listado" es el fichero listado. Así hemos inventado un nuevo (y no tan eficiente) método de copiar ficheros.
¿Qué ocurre con el comando "cat > zorro" ? cat lee cada línea escrita en el terminal (entrada estándar) y la imprime de vuelta (salida estándar) hasta que lee |_Ctrl-d_|. En este caso, la salida estándar se ha redireccionado al fichero zorro. Ahora cat sirve como un editor rudimentario:
/home/larry$ cat > zorro
El rapido zorro marron salta sobre el descuidado perro.
pulsa Ctrl-d
Ahora se ha creado el fichero zorro que contiene la frase "El rapido zorro marron salta sobre el descuidado perro". Un último uso del versátil comando cat es concatenar ficheros. cat imprimirá cada fichero dado como parámetro, uno despues de otro. El comando "cat listado zorro" imprimirá el listado del directorio /usr/bin, y luego la tonta frase. Así, el comando "cat listado zorro > listyzorro" creará un nuevo fichero conteniendo los contenidos de listado y zorro.
Redireccionar la entrada
Así como cuando se redirecciona la salida estándar, es posible redireccionar la entrada. En lugar de que un programa lea su entrada desde el teclado, la leerá desde un fichero. Como redireccionar la entrada está relacionado con redireccionar la salida, parece natural que "<" sea el carácter para redireccionar la entrada. Éste también se usa después del comando que se desee ejecutar.
Esto es generalmente útil si se tiene un fichero de datos y un comando que espera sus datos desde la entrada estándar. Muchos comandos permiten especificar un fichero sobre el cual operar, así que en las actividades diarias el "<" no se usa tanto como otras técnicas.
Las tuberías
Muchos comandos Unix producen gran cantidad de información. Por ejemplo, es normal que un comando como "ls /usr/bin" produzca más salida que la que se puede ver en pantalla. Para que se pueda ver toda la información de un comando como "ls /usr/bin" , es necesario usar otro comando Unix llamado more4. more parará cada vez que la pantalla se llene de información. Por ejemplo, "more < /etc/rc" mostrará el fichero /etc/rc como lo haría "cat /etc/rc" , excepto que more permite leerlo. more también admite el comando "more /etc/rc" , y esa es la forma normal de invocarlo.
Sin embargo, eso no ayuda al problema de que "ls /usr/bin" muestre más información de la que se pueda ver. "more < ls /usr/bin" no funciona, ¡la redirección de entrada sólo funciona con ficheros, no comandos! Se podría hacer esto:
/home/larry$ ls /usr/bin > temp-ls
/home/larry$ more temp-ls
..
/home/larry$ rm temp-ls
Pero, Unix propone una forma más limpia de hacerlo. Se puede usar el comando "ls /usr/bin _ more". El carácter "_" es una tubería. Como una tubería de agua, una tubería Unix controla el flujo. En vez de agua, se controla el flujo de información.
Los filtros son programas muy útiles para usarse en conjunción con las tuberías. Un filtro es un programa que lee la entrada estándar, la cambia de alguna manera, y la saca por la salida estándar.
more es un filtro, lee los datos que coge de la entrada estándar y los muestra por la salida estándar pantalla a pantalla, permitiendo leer el fichero. more no es un gran filtro porque su salida no se puede enviar a otro programa.
Otros filtros incluyen los programas cat, sort, head, y tail. Por ejemplo, si se quiere leer sólo las primeras diez líneas de la salida de ls, se puede usar "ls /usr/bin _ head" .
1 |_C-t_|significa mantener pulsada la tecla marcada como "Ctrl", y apretar la tecla "t". Luego soltar ambas.
2 "cp /etc/passwd esto-es-un-fichero-largo"
3 Para lectores impacientes, el comando que se debe usar es more. Sin embargo, hay que hablar un poco sobre algo más antes de llegar ahí.
4 Se llama more porque ese es el indicador que originalmente mostraba: "--more--". En varias versiones de Linux el comando more es identico a un comando más avanzado que hace todo lo que more puede hacer y más aún. Como demostración de que los programadores de ordenadores son malos cómicos, llamaron a este nuevo programa "less".