- cat – Concatena archivos
- sort – Ordena líneas de texto
- uniq – Reporta u omite lineas repetidas
- grep – Imprime lineas que coincidan con un patrón
- wc – Imprime el número de líneas, palabras y bytes para cada archivo
- head – Imprime la primera parte de un archivo
- tail – Imprime la última parte de un archivo
- tee – Lee de la entrada estándar y escribe en la salida estándar y en archivo
Entrada, salida y error estándar
Muchos de los programas que hemos usado hasta ahora producen algún tipo de salida. Esta salida, a menudo es de dos tipos. Primero, tenemos los resultados del programa; o sea, los datos que el programa está diseñado para producir, y segundo, tenemos mensajes de estado y de error que nos dice como va el programa. Si miramos un comando como ls, podemos ver que muestra sus resultados y sus mensajes de error en la pantalla.
Siguiendo con el tema Unix de “todo es un archivo”, programas como ls en realidad mandan sus resultados a un archivo especial llamado standard output o salida estándar (a menudo expresado como stdout) y sus mensajes de estado a otro archivo llamado standard error o error estándar (stderr). Por defecto, tanto la salida estándar como el error estándar están enlazados a la pantalla y no se guardan en un archivo en el disco.
Además muchos programas toman la entrada de una aplicación llamada standard input o entrada estándar (stdin) que está, por defecto, asociada al teclado.
La redirección I/O nos permite cambiar donde va la salida y de donde viene la entrada. Normalmente, la salida va a la pantalla y la entrada viene del teclado, pero con la redirección I/O, podemos cambiarlo.
Redirigiendo la salida estándar
La redirección I/O nos permite redefinir donde va la salida estándar. Para redirigir la salida estándar a otro archivo en lugar de a la pantalla, usamos el operador de redirección “>” seguido del nombre del archivo. ¿Para qué querríamos hacer ésto? A menudo es útil almacenar la salida de un comando en un archivo. Por ejemplo, podríamos decirle al shell que mande la salida del comando ls al archivo ls-output.txt en lugar de a la pantalla:
[me@linuxbox ~]$ ls -l /usr/bin > ls-output.txt
Aquí, hemos creado un largo listado del directorio /usr/bin y hemos mandado los resultados al archivo ls-output.txt. Examinemos la salida redirigida del comando:
[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me me 167878 2008-02-01 15:07 ls-output.txt
Bien, un bonito y largo archivo de texto. Si vemos el archivo con less, veremos que el archivo ls-output.txt en efecto contiene el resultado del nuestro comando ls:
[me@linuxbox ~]$ less ls-output.txt
Ahora, repitamos nuestra prueba de redirección, pero esta vez con un giro. Cambiaremos el nombre del directorio a uno que no exista:
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt
ls: cannot access /bin/usr: No such file or directory
Recibimos un mensaje de error. Ésto tiene sentido ya que especificamos el directorio /bin/usr que no existe, pero ¿por qué ha mostrado el mensaje de error en la pantalla en lugar que ser redirigido al archivo ls-output.txt? La respuesta es que el programa ls no manda sus mensajes de error a la salida estándar. En lugar de eso, como la mayoría de los programas bien escritos de Unix, manda sus mensajes de error al error estándar. Como sólo hemos redirigido la salida estándar y no el error estándar, el mensaje de error todavía es enviado a la pantalla. Veremos como redirigir el error estándar en un minuto, pero primero, veamos que ha ocurrido a nuestro archivo de salida:
[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me me 0 2008-02-01 15:08 ls-output.txt
¡El archivo ahora tiene tamaño cero! Ésto es porque, cuando redirigimos la salida con el operador de redirección “>”, el archivo de destino siempre se sobreescribe desde el principio. Como nuestro comando ls no generó resultados y sólo un mensaje de error, la operación de redirección comenzó a reescribir el archivo y paró a causa del error, truncándose. De hecho, si alguna vez necesitamos realmente un archivo truncado (o crear un archivo nuevo vacío) podemos usar un truco como éste:
[me@linuxbox ~]$ > ls-output.txt
Simplemente usando el operador de redirección con ningún comando precediéndolo truncará un archivo existente o creará un archivo nuevo vacío.
Pero, ¿cómo podemos añadir la salida redirigida a un archivo en lugar de sobreescribir el archivo desde el principio? Para eso, usamos el operador de redirección “>>”, así:
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
Usando el operador “>>” tendremos como resultado que la salida se añadirá al archivo. Si el archivo no existe, se creará igual que como con el operador “>” que hemos estado usando. Probémoslo:
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l /usr/bin >> ls-output.txt
[me@linuxbox ~]$ ls -l ls-output.txt
-rw-rw-r-- 1 me me 503634 2008-02-01 15:45 ls-output.txt
Hemos repetido el comando tres veces resultando un archivo de salida tres veces más grande.
Redirigiendo el error estándar
Redirigir el error estándar carece de la facilidad de un operador de redirección dedicado. Para redirigir el error estándar debemos referirnos a su descriptor de archivo (file descriptor). Un programa puede producir salidas en una de varias cadenas de archivos numeradas. Aunque nos hemos referido a las tres primeras de estas cadenas de archivos como entrada estándar, salida estándar y error estándar, el shell se refiere a ellas internamente como los descriptores de archivo 0, 1 y 2 respectivamente. El shell proporciona una notación para los archivos redirigidos utilizando el número descriptor de archivo. Como el error estándar es el mismo que el descriptor de archivo número 2, podemos redirigir el error estándar con esta notación:
[me@linuxbox ~]$ ls -l /bin/usr 2> ls-error.txt
El descriptor de archivo “2” se coloca inmediatamente antes del operador de redirección para realizar la redirección del error estándar al archivo ls-error.txt.
Redirigiendo la salida estándar y el error estándar a un archivo
Hay casos en que querremos capturar toda la salida de un comando a un archivo. Para hacerlo, debemos redirigir tanto la salida estándar como el error estándar al mismo tiempo. Hay dos formas de hacerlo. Primero, la forma tradicional, que funciona con versiones antiguas del shell:
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt 2>&1
Utilizando este método, conseguiremos dos redirecciones. Primero redirigimos la salida estándar al archivo ls-output.txt y después redirigimos el descriptor de archivo 2 (error estándar) al descriptor de archivo 1 (salida estándar) usando la notación 2>&1.
Fíjate que el orden de las redirecciones es fundamental. La redirección del error estándar siempre debe ocurrir despúes de redirigir la salida estándar o no funcionará. En el ejemplo anterior:
>ls-output.txt 2>&1
se redirige el error estándar al archivo ls-output.txt, pero si cambiamos el orden a
2>&1 >ls-output.txt
el error estándar es redirigido a la pantalla.
Versiones recientes de bash proporcionan un segundo, y más eficiente método para realizar esta redirección combinada:
[me@linuxbox ~]$ ls -l /bin/usr &> ls-output.txt
En este ejemplo, usamos la notación simple &> para redirigir tanto la salida estándar como el error estándar al archivo ls-output.txt. Podrías también añadir la salida estándar y el error estándar a un archivo existente así:
[me@linuxbox ~]$ ls -l /bin/usr &>> ls-output.txt
Eliminando salidas innecesarias
Algunas veces “el silencio es oro”, y no queremos salida de un comando, sólo queremos ignorarla. Ésto se aplica particularmente a los mensajes de estado y de error. El sistema proporciona una forma de hacerlo redireccionando la salida a un archivo especial llamado “dev/null”. Este archivo es un dispositivo de sistema llamado un cubo de bits que acepta entradas y no hace nada con ellas. Para suprimir los mensajes de error de un comando, hacemos esto:
[me@linuxbox ~]$ ls -l /bin/usr 2> /dev/null
Redireccionando la entrada estándar
Hasta ahora, no hemos encontrado ningún comando que haga uso de la entrada estándar (en realidad sí lo hemos hecho, pero revelaremos la sorpresa un poco más tarde), así que necesitamos presentar uno.
cat – Concatenando archivos
El comando cat lee uno o más archivos y los copia a la salida estándar de la siguiente forma:
cat [file...]
En la mayoría de los casos, puedes pensar que cat es un análogo al comando TYPE de DOS. Puedes usarlo para mostrar archivos sin paginar, por ejemplo:
[me@linuxbox ~]$ cat ls-output.txt
mostrará el contenido del archivo ls-output.txt. cat a menudo se usa para mostrar archivos de texto cortos. Como cat puede aceptar más de un archivo como argumento, puede ser usado también para unir archivos. Imagina que hemos descargado un gran archivo que ha sido dividido en múltiples partes (los archivos multimedia a menudo está divididos de esta forma en Usenet), y queremos unirlos de nuevo. Si los archivos se llamaran:
movie.mpeg.001 movie.mpeg.002 ... movie.mpeg.099
podríamos unirlos de nuevo con este comando:
cat movie.mpeg.0* > movie.mpeg
Como los comodines siempre expanden sus resultados en orden alfabético, los argumentos se distribuirán en el orden correcto.
Todo esto está muy bien, pero ¿qué tienen esto que ver con la entrada estándar? Nada todavía, pero probemos algo más. Que pasa si usamos “cat” sin argumentos:
[me@linuxbox ~]$ cat
No ocurre nada, sólo se queda quieto como si se hubiera quedado colgado. Podría parecer eso, pero realmente está haciendo lo que se supone que debe hacer.
Si no le damos argumentos a cat, lee de la entrada estándar y como la entrada estándar está, por defecto, asignada al teclado, ¡está esperando a que tecleemos algo! Prueba a añadir el siguiente texto y pulsa Enter:
[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
Ahora, pulsa Ctrl-d (p.ej., pulsa la tecla Ctrl y luego pulsa “d”) para decirle a cat que ha alcanzado el final del archivo (EOF – end of file) en el salida estándar:
[me@linuxbox ~]$ cat
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
En ausencia de nombres de archivo como argumentos, cat copia la entra estándar a la salida estándar, así que vemos nuestra línea de texto repetida. Podemos usar este comportamiento para crear archivos de texto cortos. Digamos que queremos crear un archivo llamado “lazy_dog.txt” conteniendo el texto de nuestro ejemplo. Podríamos hacer ésto:
[me@linuxbox ~]$ cat > lazy_dog.txt
The quick brown fox jumped over the lazy dog.
Escribe el comando seguido del texto que queremos colocar en el archivo. Recuerda pulsar Ctrl-d al final. Usando la línea de comandos, ¡hemos implementado el procesador de texto más tonto del mundo! Para ver nuestros resultados, podemos usar cat para copiar el archivo a stdout de nuevo:
[me@linuxbox ~]$ cat lazy_dog.txt
The quick brown fox jumped over the lazy dog.
Ahora que conocemos como cat acepta la entrada estándar, además de nombres de archivo como argumentos, probemos redirigiendo la entrada estándar:
[me@linuxbox ~]$ cat < lazy_dog.txt
The quick brown fox jumped over the lazy dog.
Usando el operador de redirección “<”, hemos cambiado el origen de la entrada estándar del teclado al archivo lazy_dog.txt. Vemos que el resultado es el mismo que pasarle un nombre de archivo como argumento, pero sirve para demostrar el uso de un archivo como fuente de la entrada estándar. Otros comandos hacer un mejor uso de la entrada estándar, como veremos pronto.
Antes de seguir, echa un vistazo a la man page de cat, ya que tiene varias opciones interesantes.
Pipelines (Tuberías)
La capacidad de los comandos de leer datos de la entrada estándar y mandarlos a la salida estándar la utiliza una función del shell llamada pipeline (tubería). Usando el operador pipe (tubo) “|” (la barra vertical), la salida estándar de un comando puede ser canalizada hacia la entrada estándar de otro:
comando1 | comando2
Para demostrarlo plenamente, vamos a necesitar algunos comandos. ¿Recuerdas que dijimos que había uno que ya conocíamos que acepta entrada estándar? Es less. Podemos usar less para mostrar, página a página, la salida de cualquier comando que mande sus resultados a la salida estándar:
[me@linuxbox ~]$ ls -l /usr/bin | less
¡Ésto es tremendamente práctico! Usando esta técnica, podemos examinar convenientemente la salida de cualquier comando que produzca salida estándar.
La diferencia entre > y |
A primera vista, podría ser difícil de comprender la redirección realizada por el operador pipeline | frente a la del operador de redirección >. Simplificando, el operador de redirección conecta un comando con un archivo mientras que el operador pipeline conecta la salida de un comando con la entrada de un segundo comando:
comando1 > archivo1
comando1 | comando2
Mucha gente intentará lo siguiente cuando están aprendiendo los pipelines, “sólo mira lo que sucede.”
comando1 > comando2
Respuesta: A veces algo realmente malo.
Aquí tenemos un ejemplo real enviado por un lector que estaba administrando una aplicación de servidor basada el Linux. Como superusuario, hizo ésto:
# cd /usr/bin
# ls > less
El primer comando le colocó en el directorio donde están almacenados la mayoría de los programas y el segundo comando le dijo al shell que sobrescriba el archivo less con la salida del comando ls. Como el directorio /usr/bin ya contenía un archivo llamado “less” (el programa less), el segundo comando sobrescribió el archivo del programa less con el texto de ls y en consecuencia destruyendo el programa less en su sistema.
La lección aquí es que el operador de redirección crea o sobrescribe archivos silenciosamente, así que necesitas tratarlo con mucho respeto.
Filtros
Los pipelines a menudo se usan para realizar complejas operaciones con datos. Es posible poner varios comandos juntos dentro de un pipeline. Frecuentemente, a los comandos usados de esta forma se les llama filtros. Los filtros toman entradas, la cambian en algo y las mandan a la salida. El primero que probaremos es sort. Imagina que queremos hacer una lista combinada de todos los programas ejecutables en /bin y en /usr/bin, que los ponga en orden y los veamos:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | less
Como hemos especificado dos directorios (/bin y /usr/bin), la salida de ls debería haber consistido en dos listas ordenadas, una para cada directorio. Pero incluyendo sort, en nuestro pipeline, hemos cambiado los datos para producir una única lista ordenada.
uniq – Muestra u omite líneas repetidas
El comando uniq a menudo se usa junto con sort. uniq acepta una lista ordenada de datos de la entrada estándar o de un argumento que sea un nombre de archivo (mira la man page de uniq para saber más detalles) y, por defecto, elimina los duplicados de la lista. Así, que para estar seguro de que nuestra lista no tiene duplicados (ya sabes, algunos programas con el mismo nombre pueden aparecer tanto en el directorio /bin como en /usr/bin) añadiremos uniq a nuestro pipeline:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | less
En este ejemplo, usamos uniq para eliminar duplicados de la salida del comando sort. Si, en lugar de eso, queremos ver la lista de duplicados, añadiremos la opción “-d” a uniq así:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq -d | less
wc – Muestra el número de líneas, palabras y bytes
El comando wc (word count – contador de palabras) se usa para mostrar el número de líneas, palabras y bytes contenidos en un archivo. Por ejemplo:
[me@linuxbox ~]$ wc ls-output.txt
7902 64566 503634 ls-output.txt
En este caso muestra tres números: líneas, palabras y bytes contenidos en ls-output.txt. Como nuestros anteriores comandos, si lo ejecutamos sin argumentos, wc acepta la entrada estándar. La opción “-l” limita su salida para mostrar sólo el número de líneas. Añadirlo a un pipeline es una forma útil de contar cosas. Para ver el número de elementos que tenemos en nuestra lista ordenada, podemos hacer esto:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | wc -l
2728
grep – Imprime líneas que coinciden con un patrón
grep pattern [file...]
Cuando grep encuentra un “patrón” en el archivo, muestra las líneas que lo contienen. El patrón que grep puede encontrar puede ser muy complejo, pero por ahora nos concentraremos en coincidencias simples de texto. Trataremos patrones avanzados, llamados expresiones regulares en un capítulo posterior.
Digamos que queremos encontrar todos los archivos en nuestra lista de programas que tengan la palabra “zip” incluida en el nombre. Una búsqueda así debería darnos una idea que algunos de los programas en nuestro sistema que tienen algo que ver con la compresión de archivos. Haríamos ésto:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
Hay un par de opciones útiles para grep: “-i” que hace que grep ignore las mayúsculas cuando haga la búsqueda (normalmente las búsquedas con sensibles a las mayúsculas) y “-v” que le dice a grep que sólo muestre las lineas que no coincidan con el patrón.
head / tail – Muestra la primera/última parte de los archivos
Algunas veces no quieres toda la salida de un comando. Podrías querer sólo las primeras o las últimas líneas. El comando head muestra las primeras diez líneas de un archivo y el comando tail muestras las diez últimas. Por defecto, ambos comandos muestran diez líneas de texto, pero ésto puede ajustarse con la opción “-n”:
[me@linuxbox ~]$ head -n 5 ls-output.txt
total 343496
-rwxr-xr-x 1 root root 31316 2007-12-05 08:58 [
-rwxr-xr-x 1 root root 8240 2007-12-09 13:39 411toppm
-rwxr-xr-x 1 root root 111276 2007-11-26 14:27 a2p
-rwxr-xr-x 1 root root 25368 2006-10-06 20:16 a52dec
[me@linuxbox ~]$ tail -n 5 ls-output.txt
-rwxr-xr-x 1 root root 5234 2007-06-27 10:56 znew
-rwxr-xr-x 1 root root 691 2005-09-10 04:21 zonetab2pot.py
-rw-r--r-- 1 root root 930 2007-11-01 12:23 zonetab2pot.pyc
-rw-r--r-- 1 root root 930 2007-11-01 12:23 zonetab2pot.pyo
lrwxrwxrwx 1 root root 6 2008-01-31 05:22 zsoelim -> soelim
Puede ser usado en pipelines también:
[me@linuxbox ~]$ ls /usr/bin | tail -n 5
znew
zonetab2pot.py
zonetab2pot.pyc
zonetab2pot.pyo
zsoelim
tail tiene una opción que nos permite ver los archivos en tiempo real. Ésto es útil para ver el progreso de los archivos de logs tal como se van escribiendo. En el siguiente ejemplo, veremos el archivo messages en /var/log (o el archivo /var/log/syslog si messages no existe). Se requieren privilegios de superusuario para hacerlo en algunas distribuciones Linux, ya que el archivo /var/log/messages podría contener información de seguridad:
[me@linuxbox ~]$ tail -f /var/log/messages
Feb 8 13:40:05 twin4 dhclient: DHCPACK from 192.168.1.1
Feb 8 13:40:05 twin4 dhclient: bound to 192.168.1.4 -- renewal in 1652 seconds.
Feb 8 13:55:32 twin4 mountd[3953]: /var/NFSv4/musicbox exported to both 192.168.1.0/24 and twin7.localdomain in 192.168.1.0/24,twin7.localdomain
Feb 8 14:07:37 twin4 dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
Feb 8 14:07:37 twin4 dhclient: DHCPACK from 192.168.1.1
Feb 8 14:07:37 twin4 dhclient: bound to 192.168.1.4 -- renewal in 1771 seconds.
Feb 8 14:09:56 twin4 smartd[3468]: Device: /dev/hda, SMART Prefailure Attribute: 8 Seek_Time_Performance changed from 237 to 236
Feb 8 14:10:37 twin4 mountd[3953]: /var/NFSv4/musicbox exported to both 192.168.1.0/24 and twin7.localdomain in 192.168.1.0/24,twin7.localdomain
Feb 8 14:25:07 twin4 sshd(pam_unix)[29234]: session opened for user me by (uid=0)
Feb 8 14:25:36 twin4 su(pam_unix)[29279]: session opened for user root by me(uid=500)
Usando la opción “-f”, tail continua monitorizando el archivo y cuando se le añaden nuevas líneas, inmediatamente aparecen en la pantalla. Esto continua hasta que pulses Ctrl-c.
Tee – Lee de stdin y lo pasa a stdout y a archivos
Siguiendo con nuestra metáfora de fontanería, Linux proporciona un comando llamado tee que crea un “soporte” agarrado a nuestra tubería. El programa tee lee la entrada estándar y la copia a la salida estándar (permitiendo que los datos continúen bajando por la tubería) y a uno o más archivos. Ésto es útil para capturar el contenido de un pipeline en una fase intermedia del procesamiento. Repetiremos uno de nuestros anteriores ejemplos, esta vez incluyendo tee para capturar el listado completo del directorio al archivo ls.txt antes de que grep filtre el contenido del pipeline:
[me@linuxbox ~]$ ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
Resumiendo
Como siempre, revisa la documentación de cada comando que hemos tratado en este capítulo. Sólo hemos visto su uso más básico. Todos tienen numerosas opciones interesantes. Según vayamos ganando experiencia con Linux, veremos que la función de redirección de la línea de comandos es extremadamente útil para solucionar problemas especializados. Hay muchos comandos que hacen uso de la entrada y salida estándar, y casi todos los programas de la línea de comandos usan el error estándar para mostrar sus mensajes informativos.
Tee – Lee de stdin y lo pasa a stdout y a archivos
Siguiendo con nuestra metáfora de fontanería, Linux proporciona un comando llamado tee que crea un “soporte” agarrado a nuestra tubería. El programa tee lee la entrada estándar y la copia a la salida estándar (permitiendo que los datos continúen bajando por la tubería) y a uno o más archivos. Ésto es útil para capturar el contenido de un pipeline en una fase intermedia del procesamiento. Repetiremos uno de nuestros anteriores ejemplos, esta vez incluyendo tee para capturar el listado completo del directorio al archivo ls.txt antes de que grep filtre el contenido del pipeline:
[me@linuxbox ~]$ ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
Resumiendo
Como siempre, revisa la documentación de cada comando que hemos tratado en este capítulo. Sólo hemos visto su uso más básico. Todos tienen numerosas opciones interesantes. Según vayamos ganando experiencia con Linux, veremos que la función de redirección de la línea de comandos es extremadamente útil para solucionar problemas especializados. Hay muchos comandos que hacen uso de la entrada y salida estándar, y casi todos los programas de la línea de comandos usan el error estándar para mostrar sus mensajes informativos.
Linux tiene que ver con la imaginación
Cuando me piden que explique la diferencia entre Windows y Linux, a menudo uso una analogía con un juguete.
Windows es como una Game Boy. Vas a la tienda y compras una toda brillante y nueva en su caja. La llevas a casa, la enciendes y juegas con ella. Bonitos gráficos, sonidos chulos. Cuando pasa un rato, te cansas del juego que viene con ella y vuelves a la tienda a comprar otro. Este ciclo se repite una y otra vez. Finalmente, vuelves a la tienda y le dices a la persona que está tras el mostrador, “¡Quiero un juego que haga ésto!” sólo para que te digan que ese tipo de juego no existe porque no hay “demanda” en el mercado. Entonces dices, “¡Pero sólo necesito cambiar una cosa! La persona tras el mostrador te dice que no puedes cambiarlo. Los juegos se venden en sus cartuchos. Descubres que tu juguete está limitado a los juegos que otros han decidido que necesitas y ya está.
Linux, al contrario, es como el mecano más grande del mundo. Lo abres y sólo es una gran colección de partes. Un montón de puntillas, tornillos, tuercas, engranajes, poleas, motores todos de acero y algunas sugerencias sobre qué puedes construir. Así que empiezas a jugar con él. Construyes una de las sugerencias y luego otra. Después de un rato descubres que tienes tus propias ideas de qué construir. Nunca más tienes que volver a la tienda, ya que tienes todo lo que necesitas. El mecano se adapta a tu imaginación. Hace lo que tú quieres.
Tu elección de juguetes es, por supuesto, algo personal, así que ¿qué juguete encontrarías más satisfactorio?
No hay comentarios:
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.