Redirección de salida
La salida de una orden de UNIX suele ir a la pantalla. Esto no debería
suponer una gran noticia pues nuestra orden emblemática, el
entrañable ls
no cesa de mostrarnos por la pantala
información de más y más ficheros.
Este comportamiento por defecto se puede cambiar. Podemos pedir a
una orden, o a un programa en general, que nos escriba en un fichero
lo que, de otro modo, sacaría por la pantalla. Se hace con
el símbolo de mayor que (>
):
<gyermo@ENCINA>/usuarios/profes/gyermo$ ls -l
total 2382
drwxr-xr-x 2 gyermo profes 512 ago 22 20:01 ARGUMENTOS
-rwx------ 1 gyermo profes 99 abr 17 2002 backup
drwxr-xr-x 2 gyermo profes 512 abr 14 2010 bin
drwxr-xr-x 12 gyermo profes 512 ago 22 17:30 CAJAFUERTE
drwxr-xr-x 2 gyermo profes 512 ago 21 13:31 CARTAS
-rw-r--r-- 1 gyermo profes 50 feb 4 2009 chgrp.2
-rw------- 1 gyermo profes 1191936 abr 1 2005 gyermo-encina-2005-03.tar.gz
drwx------ 2 gyermo profes 512 dic 23 2003 mail
drwxr-xr-x 2 gyermo profes 2048 feb 27 2002 MANTEJO
drwx------ 21 gyermo profes 1024 ago 18 19:12 PRIVADO
d---r-xrwx 2 gyermo profes 512 ago 18 02:24 PRUEBA
drwxr-xr-x 3 gyermo profes 512 jul 3 2006 public_html
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION3
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION6
drwx------ 3 gyermo profes 512 mar 2 2010 TEMP
<gyermo@ENCINA>/usuarios/profes/gyermo$ ls -l > salida
<gyermo@ENCINA>/usuarios/profes/gyermo$ ls -l salida
-rw-r--r-- 1 gyermo profes 1020 ago 23 18:24 salida
Como vemos, en la segundo ejecución de ls
,
hemos desviado la salida por la pantalla al fichero salida
y,
consecuentemente, tenemos ese fichero nuevo. Para ver su
contenido, necesitamos una orden que muestre el contenido
de un fichero. Si el hombre (man
) nos ayuda
con la documentación de las órdenes, el
gato (cat
, de concatenate) nos
muestra el contenido de los ficheros:
<gyermo@ENCINA>/usuarios/profes/gyermo$ cat salida
total 2382
drwxr-xr-x 2 gyermo profes 512 ago 22 20:01 ARGUMENTOS
-rwx------ 1 gyermo profes 99 abr 17 2002 backup
drwxr-xr-x 2 gyermo profes 512 abr 14 2010 bin
drwxr-xr-x 12 gyermo profes 512 ago 22 17:30 CAJAFUERTE
drwxr-xr-x 2 gyermo profes 512 ago 21 13:31 CARTAS
-rw-r--r-- 1 gyermo profes 50 feb 4 2009 chgrp.2
-rw------- 1 gyermo profes 1191936 abr 1 2005 gyermo-encina-2005-03.tar.gz
drwx------ 2 gyermo profes 512 dic 23 2003 mail
drwxr-xr-x 2 gyermo profes 2048 feb 27 2002 MANTEJO
drwx------ 21 gyermo profes 1024 ago 18 19:12 PRIVADO
d---r-xrwx 2 gyermo profes 512 ago 18 02:24 PRUEBA
drwxr-xr-x 3 gyermo profes 512 jul 3 2006 public_html
-rw-r--r-- 1 gyermo profes 0 ago 23 18:24 salida
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION3
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION6
drwx------ 3 gyermo profes 512 mar 2 2010 TEMP
Si peferís verlo con vuestro editor favorito, pues
también podéis. Si sois observadores notaréis
que hemos pillado al fichero salida
in fraganti. Cuando ls
le ha echado la
foto, estaba ya creado, porque se crea antes de dar el control
a ls
, pero aún no tenía su contenido.
Si lo que queremos es que la orden desvíe la salida
de la pantalla a un fichero, pero que la añada al final
sin destruir lo que en el fichero hubiera, debemos doblar
el carácter de mayor que (>>
).
Vamos a añadir la fecha y la hora en que hemos hecho
el listado al fichero salida
. ¿Os atrevéis
a hacerlo sin mirar la solución que se os pone a
continuación?
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo "Listado realizado el 23 de agosto, a las siete" >> salida
<gyermo@ENCINA>/usuarios/profes/gyermo$ cat salida
total 2382
drwxr-xr-x 2 gyermo profes 512 ago 22 20:01 ARGUMENTOS
-rwx------ 1 gyermo profes 99 abr 17 2002 backup
drwxr-xr-x 2 gyermo profes 512 abr 14 2010 bin
drwxr-xr-x 12 gyermo profes 512 ago 22 17:30 CAJAFUERTE
drwxr-xr-x 2 gyermo profes 512 ago 21 13:31 CARTAS
-rw-r--r-- 1 gyermo profes 50 feb 4 2009 chgrp.2
-rw------- 1 gyermo profes 1191936 abr 1 2005 gyermo-encina-2005-03.tar.gz
drwx------ 2 gyermo profes 512 dic 23 2003 mail
drwxr-xr-x 2 gyermo profes 2048 feb 27 2002 MANTEJO
drwx------ 21 gyermo profes 1024 ago 18 19:12 PRIVADO
d---r-xrwx 2 gyermo profes 512 ago 18 02:24 PRUEBA
drwxr-xr-x 3 gyermo profes 512 jul 3 2006 public_html
-rw-r--r-- 1 gyermo profes 0 ago 23 18:24 salida
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION3
drwxr-xr-x 2 gyermo profes 512 mar 19 2002 SESION6
drwx------ 3 gyermo profes 512 mar 2 2010 TEMP
Listado realizado el 23 de agosto, a las siete
Redirección de errores
Sabéis de las asignaturas de programación que un programa en
C tiene, desde su nacimiento, tres ficheros abiertos: la entrada
estándar (
stdin
), la salida estándar
(
stdout
) y el canal de errores estándar
(
stderr
).
El primero está conectado por defecto al teclado del terminal.
Los dos últimos vierten, por defecto, su salida a la
pantalla. Escribamos un pequeño programa en C que use
la salida estándar y el canal de errores estándar:
#include <stdio.h>
int main(void)
{printf("Esto va a la salida estándar.\n");
fprintf(stdout, "Esto también va a la salida estándar.\n");
fprintf(stderr, "Esto va al canal de errores.\n");
return 0;}
Si lo ejecutamos, vemos los tres mensajes y, por lo visto en el
apartado anterior, si redirigimos la salida a un fichero, solo
vemos los mensajes de error:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ gcc errores.c -o errores
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores
Esto va a la salida estándar.
Esto también va a la salida estándar.
Esto va al canal de errores.
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores > salida
Esto va al canal de errores.
Podemos, también, redirigir el canal de errores. Para ello,
usamos los mismos símbolos que para la salida estándar,
pero anteponiendo un 2:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores 2> salida
Esto va a la salida estándar.
Esto también va a la salida estándar.
Podemos, por supuesto, redirigir la salida estándar a un fichero
y el canal de errores a otro. Pero, si queremos, que ambos canales
vayan al mismo fichero, hay que tener cuidado. La primera forma que
se nos puede ocurrir, no va a funcionar:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores > salida 2> salida
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ cat salida
Esto va a la salida estándar.
Esto también va a la salida estándar.
El ordenador, al abrir el fichero de salida dos veces, machaca el
contenido y no funciona. Debemos decirle algo como: manda el
canal de errores a donde he mandado la salida estándar.
Esto se hace con la siguiente sintaxis:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores > salida 2>&1
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ cat salida
Esto va al canal de errores.
Esto va a la salida estándar.
Esto también va a la salida estándar.
Fichero nulo
Existe un fichero especial en UNIX que, todo lo que se envía
a él, desaparece. Es como un agujero negro,
pero en lugar de succionar materia, succiona datos.
Su nombre es /dev/null
Si, por ejemplo, queremos que el ordenador no nos moleste con
los mensajes de errores, podemos redireccionar el canal de
errores a /dev/null
:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores 2>/dev/null
Esto va a la salida estándar.
Esto también va a la salida estándar.
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ cat /dev/null
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$
Como podéis comprobar con el cat
,
/dev/null
engulle y engulle, y no queda nada.
A veces, no queremos que una orden o programa nos moleste en
absoluto, ni con su salida, ni con sus mensajes de error.
En ese caso, redirigimos ambos canales a /dev/null
:
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ errores 2>/dev/null >&2
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$ cat /dev/null
<gyermo@ENCINA>/usuarios/profes/gyermo/ERRORES$
Redirección de entrada
La orden cat
es la más sencilla de una serie
de órdenes que vamos a tratar en esta sesión.
Para que este aspecto de cat
salga a la luz, hay
que invocarla sin argumentos. Hacedlo. Teclead,
a continuación algo y ved lo que pasa:
<gyermo@ENCINA>/usuarios/profes/gyermo$ cat
Hola
Hola
¿Qué pasa aquí?
¿Qué pasa aquí?
eco, eco, eco...
eco, eco, eco...
^C<gyermo@ENCINA>/usuarios/profes/gyermo$
Cuando cat
se invoca sin argumentos, la orden toma
todo lo que le llega por la entrada estándar y lo vuelca
tal cual por la salida estándar. El efecto neto es
esa especie de eco que observáis. Para que el ordenador
interrumpa esta orden (u otras que no quieran parar o que
estén colgadas), podéis pulsar CTRL-C
(presionáis la tecla Ctrl y, sin soltarla, presionáis
la tecla C).
Podemos usar la orden cat
como un rudimentario
editor para crear un nuevo fichero de texto, sin más
que redireccionar su salida estándar. Vamos a probarlo
dentro de un nuevo directorio de nombre SEMANA
,
donde vamos a crear un fichero llamado semana.txt
,
con el nombre de los siete días de la semana:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat > semana.txt
lunes
martes
miércoles
jueves
viernes
sábado
domingo
[[Pulsad aquí CTRL-D]]
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat semana.txt
lunes
martes
miércoles
jueves
viernes
sábado
domingo
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$
Debéis pulsar el carácter de CTRL-D en lugar
del de CTRL-C, porque este último se usa para abortar
una orden. Sin embargo, CTRL-D significa fin de fichero
o fin de transmisión, sin que el ordenador
interprete que ha ocurrido un error o una parada anormal.
Como se ha comentado antes, cat
pertenece a una
familia de órdenes de UNIX conocida como filtros.
Consisten en que aceptan datos por la entrada estándar,
hacen algo con ellos y producen una salida por la salida
estándar. El caso de cat
es el más
simple porque no hace nada con los datos. Pero veamos otro
ejemplo más útil: la orden sort
.
sort
es suerte en catalán, así
que, como homenaje, tecleemos la orden y el nombre de las
provincias catalanas para ver qué sucede:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ sort
Barcelona
Tarragona
Lérida
Gerona
[[Pulsad aquí CTRL-D]]
Barcelona
Gerona
Lérida
Tarragona
Nadie quita que la orden nos dé buena suerte, pero más
bien su nombre viene del inglés. Esta orden ordena las
líneas que le lleguen por la entrada estándar y
las imprime ya ordenadas por la salida estándar.
Pero este apartado, en realidad, trata de la redirección de la
entrada de una orden. Después de esta introducción,
estamos en condiciones de abordarla. Consiste en poder cambiar
el comportamiento por defecto de una orden para que, en lugar
de leer sus datos de la entrada estándar, lo haga del
fichero cuyo nombre le proporcionemos. El mecanismo es muy
sencillo. Lo vamos a probar ordenando la lista de los días
de la semana que elaboramos al principio de este apartado:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ sort < semana.txt
domingo
jueves
lunes
martes
miércoles
sábado
viernes
El filtro grep
Quizá uno de los filtros que más se usen sea
grep
. Además, es el que más hace
honor al nombre de filtro. Su cometido es dejar pasar
todo aquello que case con el primer argumento y retener (filtrar)
todo lo demás. Lo mejor es verlo en funcionamiento
en un ejemplo. Veamos qué días de la semana
tienen al menos una 's' en su nombre:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep "s" < semana.txt
lunes
martes
miércoles
jueves
viernes
sábado
En realidad, el primer argumento no deja de ser una
expresión regular, solo que de otro tipo de las
ya vistas. También tienen caracteres especiales.
Por ejemplo, para ver qué días de la semana
acaban en 's' y cuáles, empiezan con 's', usamos:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep "s$" < semana.txt
lunes
martes
miércoles
jueves
viernes
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep "^s" < semana.txt
sábado
También valen las expresiones con corchetes que vimos
en las otras expresiones regulares y algunas otras más,
más o menos estandarizadas. La orden grep
admite como opción -v
. En ese caso,
el filtro lo realiza al revés: filtra lo que
coincida y deja pasar lo que no coincida. Por ejemplo,
pidamos a grep
que nos diga qué días
de la semana no tienen vocales débiles:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep -v "[iu]" < semana.txt
martes
sábado
Lo que no es igual que esto otro:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep "[^iu]" < semana.txt
lunes
martes
miércoles
jueves
viernes
sábado
domingo
En este caso, lo que le pedimos a grep
es
aquellos días de la semana que contengan al menos
una letra que no sea una vocal débil.
Filtros cut, paste y uniq
Estos filtros sirven para quedarse con parte de la información
o reformatearla. El primero, nos sirve para quedarnos con
una parte de la información que aparezca en cada línea.
Imaginemos que queremos quedarnos con los tres primeros caracteres
de los nombres de los días de la semana, para usarlos
luego como abreviatura:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cut -c 1-3 < semana.txt
lun
mar
mié
jue
vie
sáb
dom
También se puede cortar no por caracteres exactos, sino
por campos, separados por espacio. Por ejemplo, si queremos
que se imprima por la pantalla la fecha de hoy,
podemos cortar por campos, basándonos en la orden
date
:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ date > hoy.txt
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat hoy.txt
jueves 25 de agosto de 2011 01H40'59" CEST
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cut -f 2-6 -d " " < hoy.txt
25 de agosto de 2011
Con la opción -f
seleccionamos los campos que
queremos y con la opción -d
decimos cuál
es el separador de los campos.
Como complemento a la orden cut
existe la orden
paste
. Toma una línea de cada uno de los
ficheros que pongamos como argumentos y las combina en una
única línea en la salida. Y así, con todas.
Usémoslo para anteponer un número a cada día
de la semana, separado por un guion:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat > numeros.txt
1
2
3
4
5
6
7
[[Pulsad aquí CTRL-D]]
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ paste -d "-" numeros.txt semana.txt
1-lunes
2-martes
3-miércoles
4-jueves
5-viernes
6-sábado
7-domingo
De nuevo, el separador entre los ficheros se indica con la
opción -d
.
La última de las órdenes, es muy sencilla.
Elimina las líneas repetidas que vayan seguidas de la entrada
antes de pasarlas a la salida:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat > salida.txt
una
una
una
otra
otra
una
una
[[Pulsad aquí CTRL-D]]
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ uniq < salida.txt
una
otra
una
-
Usando las órdenes que hemos visto hasta ahora y con
la ayuda de ficheros intermedios, decir cuáles son
los usuarios que poseen ficheros en el directorio
/usr/bin
Otros filtros útiles
Los siguientes filtros también se usan habitualmente:
more
: saca las líneas página
a página, permitiendo que se pulse espacio entre
ellas. Por ejemplo, probad con:
more < /etc/services
.
Y observad
las diferencias con cat
head
: muestra las primeras líneas
de la entrada. Probad con:
head < /etc/services
tail
: imprime las últimas líneas.
Probad con:
tail < /etc/services
wc
(word count): nos da el
número de líneas, palabras y caracteres
de la entrada. Probadlo echando los servicios al wc:
wc < /etc/services
Encadenamiento de filtros
Todos los filtros que hemos visto se pueden encadenar.
Consiste esto en que la salida de un filtro sirve como
entrada para el siguiente. Se usa para indicar el encadenamiento el
carácter de tubería (|
).
Esta función permite ahorrarnos cantidad de ficheros intermedios
para hacer una operación. Por ejemplo, para
imprimir la fecha de hoy, sin necesidad de usar un fichero
auxiliar, como hicimos más arriba, podemos poner:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ date | cut -f 2-6 -d " "
25 de agosto de 2011
Cuando montamos una cadena larga, se dispone de la orden
tee
(su significado es la letra T, pues tiene la
forma de un desvío), para desviar un resultado intermedio
a un fichero. Por ejemplo, deseamos obtener un listado de las
iniciales de los días de la semana cuyo nombre contiene
solamente letras de la 'e' a la 'z'. Deseamos que quede una
copia de los nombres completos de los días que cumplen
esa condición en el fichero salida.txt
:
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ grep -v "[a-dá]" < semana.txt | sort | tee salida.txt | cut -c 1
j
l
v
<gyermo@ENCINA>/usuarios/profes/gyermo/SEMANA$ cat salida.txt
jueves
lunes
viernes
Ejercicio
Repetir el ejercicio anterior con una
serie de órdenes dadas en una única línea
y sin la ayuda de ficheros intermedios.
Ejercicio
La orden cal
nos imprime el calendario del
mes actual. Construir una línea que nos dé en qué
cae el cuarto sábado del mes actual.
Ejercicio
En un concurso nocturno de la tele nos piden adivinar el
nombre de un animal que se pueda formar con las letras
siguientes:
Tenemos la esperanza de que el nombre se encuentre en el
fichero situado en
/usuarios/profes/gyermo/bin/animales.txt
.
Responde, con ayuda del ordenador, a las siguientes
preguntas:
- ¿Cuántos nombres de animales tiene
el fichero?
- ¿Cuántas veces tengo que lograr
pasar a directo para estar seguro de acertar
el animal?
- Ya cerca del final del programa, nos dan una
pista: el nombre del animal acaba en A.
Si el animal está en nuestra lista,
¿cuántas posibilidades hay
ahora de acertarlo?
Tuberías con nombre
Unix tiene la posibilidad de crear ficheros especiales
conocidos como tuberías con nombre
(en inglés, named pipes). Estos ficheros
se denominan así porque actúan como las
tuberías reales. Se puede añadir agua a la
tubería (escribir) o sacar agua de ella (leer).
Además, el agua que se saca es la primera que
se metió (disciplina FIFO).
Vamos a crear una tubería con nombre:
<T>/usuarios/gyermo/PRIVADO/SO/PRACTS/TUBOS$ /sbin/mknod tubo1 p
<T>/usuarios/gyermo/PRIVADO/SO/PRACTS/TUBOS$ ls -l
total 0
prw-r--r-- 1 gyermo profes 0 Mar 20 13:23 tubo1
Hay que especificar la ruta completa de la orden
mknod
porque se encuentra en un directorio
de herramientas de administración del sistema
que no está
en la variable de entorno PATH
de los usuarios
normales.
<ENCINA>/home/gyermo/PRIVADO/TUBOS$ mknod tubo1 p
<ENCINA>/home/gyermo/PRIVADO/TUBOS$ ls -l
total 0
prw-r--r-- 1 gyermo profes 0 mar 19 23:34 tubo1
En este caso, mknod
sí se encuentra en el
PATH
.
Como veis, hay que dar la orden especial
mknod
para crear
la tubería. Su página de manual
se encuentra en la sección
1m (donde están las órdenes de
administración del sistema).
Depués de crear la tubería
con mknod
, aparece en el directorio como
un fichero más
sólo que ls -l
indica mediante
una p
que
se trata de una tubería. Se llama tubería con
nombre por eso, porque precisamente tenemos que darle un
nombre para que aparezca en el directorio.
Vamos a usar la tubería para comunicarnos. Abrid otra ventana
de terminal e id al mismo directorio donde creasteis
la tubería. En una de las ventanas teclead:
cat < tubo1
En la otra:
cat > tubo1
A partir de esos momentos, todo lo que tecleéis en la segunda
ventana aparecerá en la primera.
Para acabar, podéis teclear
en la segunda ventana el carácter de fin de fichero
(CTRL+D
).
Por lo tanto, para usar una tubería con
nombre, lo único que hay que hacer es que un proceso la abra
para lectura, otro la abra para escritura y que se comuniquen
mediante las funciones de lectura y escritura en los ficheros.
Ejercicio
Podéis intentar hacer como en el ejemplo del apartado anterior
pero que la comunicación sea bidireccional.
Crearéis así un rudimentario talk
.
Si desesperáis
y no lo conseguís, podéis ver cómo hacerlo
aquí.
Órdenes de la shell relacionadas.
cat
- muestra el contenido de ficheros
sort
- filtro de ordenación
grep
- filtro para seleccionar líneas
cut
- filtro para seleccionar columnas
paste
- pega varios ficheros en columnas
uniq
- filtro que elimina líneas repetidas seguidas
more
- saca el contenido página a página
head
- filtro que muestra las primeras líneas de un
fichero
tail
- filtro que muestra las últimas líneas de un
fichero
wc
- filtro que cuenta líneas, palabras y caracteres
date
- muestra la fecha y hora actuales
tee
- filtro que desvía una copia de los datos a un
fichero
cal
- imprime un calendario del mes actual
mknod
- crea ficheros especiales, entre ellos, tuberías con
nombre
Funciones de biblioteca relacionadas.
-
-
LPEs.