Página principal

De Seguridad y Calidad en Servidores Web
Saltar a: navegación, buscar

Wiki de la asignatura Seguridad y Calidad en Servidores Web del Grado de Multimedia de la Universitat Oberta de Catalunya

En este wiki encontraréis las instrucciones básicas de Linux que necesitaréis para poder hacer la práctica de la asignatura.

Contenido

GNU/Linux

Autor: Luis Talavera Méndez (2004)

Actualización y adaptación:

  • Carlos Casado Martínez (2013)
  • Kenneth Capseta Nieto (2015)

Introducción

GNU/Linux

GNU/Linux (aunque habitualmente suele conocerse como Linux) es un sistema operativo (SO) libre. Nació a partir del núcleo Linux creado en 1991 por Linus Torvalds. El núcleo (Linux) junto con el resto de aplicaciones que componen un sistema operativo (creadas en el proyecto GNU) es lo que habitualmente conocemos como GNU/Linux o, simplemente, Linux. Actualmente es ampliamente utilizado como servidor web, entre otras cosas por que puede instalarse en diferentes máquinas, es estable y libre. Así, Facebook, Gmail, LinkedIn o Yahoo utilizan servidores GNU/Linux, lo cual puede dar una idea de la importancia de este SO.

Prácticamente todas las empresas de alojamiento web (hosting en inglés) ofrecen planes de alojamiento basados en Linux. También para grandes empresas pueden crearse redes de servidores funcionando con GNU/Linux.

Para simplificar, a partir de este momento, nos referiremos a GNU/Linux como Linux, aunque conviene no olvidar que Linux es tan solo el núcleo del sistema.

El sistema operativo

La función de cualquier sistema operativo (SO) es proporcionar una interfaz para utilizar las prestaciones del hardware de un ordenador. Los programadores acceden a estas prestaciones a través del SO y pueden diseñar aplicaciones de propósito específico para usuarios finales. Éstos, a su vez, utilizan el SO para poder ejecutar dichas aplicaciones.

Linux pertenece a la familia de sistemas denominada Unix y su filosofía está heredada de este tipo de sistemas. En lo que sigue, cuando definamos muchas de las características, funcionamiento e incluso comandos de Linux, podemos asumir que se puede aplicar a prácticamente cualquier sistema Unix con mínimos cambios. Así por ejemplo, ya podemos decir que Linux es un sistema multiusuario y multitarea, es decir, permite a varios usuarios trabajar simultáneamente y ejecutar diversas aplicaciones a la vez. Estas características determinan de forma importante el funcionamiento del sistema, el cual debe garantizar que toda esta carga de trabajo simultánea se lleve a cabo de forma segura y eficiente.

Linux está organizado por capas. La capa más profunda corresponde al hardware, que proporciona una serie de servicios (proceso, gestión de ficheros, impresión, etc.). La única capa que interactúa directamente con el hardware es el núcleo (kernel). De esta manera, los programas no necesitan saber nada sobre el hardware y sólo se comunican con el núcleo. Una de las ventajas de esta estructura es que la mayoría de programas son independientes del hardware y pueden portarse de un modelo de ordenador a otro.

Las aplicaciones que funcionan sobre el núcleo constituyen el último nivel y el único visible para los usuarios. Algunas de estas aplicaciones son utilidades básicas para la gestión de la información y la ejecución de programas y ya vienen con el sistema operativo, por lo que es habitual hablar de Linux refiriéndonos no sólo al núcleo, sino también a dicho conjunto de utilidades, desarrolladas por el proyecto GNU.

¿Quién me escucha?

Una de las ideas fundamentales de Linux que deriva de la estructura de capas es que los usuarios no ‘hablan’ directamente con el sistema, sino que lo hacen a través de una aplicación denominada intérprete de comandos (shell). Esta aplicación está constantemente ‘escuchando’ todo lo que el usuario teclea e interpreta (a partir de unas ciertas reglas sintácticas) sus peticiones.

El intérprete de comandos dispone de una serie de comandos internos que él mismo ejecuta, pero, asimismo, puede ejecutar otros comandos externos, pasándoles las opciones que el usuario ha especificado. El comando cat permite visualizar el contenido de un fichero especificado por el usuario. Algunos comandos ejecutan aplicaciones que proporcionan sus propia interfaz y conjuntos de órdenes para interactúar con los usuarios, como el editor de textos vi.

El sistema de archivos

Un sistema multiusuario necesita una forma de permitir a los usuarios tener distintos ficheros con el mismo nombre. También debe permitirles organizar los ficheros en grupos lógicos. La mayoría de sistemas operativos resuelven estas cuestiones proporcionando un sistema de ficheros jerárquico.

En un sistema de este tipo los ficheros se organizan en directorios, que no son otra cosa que un tipo especial de fichero que agrupa a otros. Puesto que un directorio puede contener también otros directorios, la estructura del sistema de ficheros se asemeja a un árbol.

Organización del sistema de ficheros

Siguiendo las convenciones habituales en Unix, el sistema de ficheros de Linux se organiza en una serie de directorios estándar de propósito específico. Algunos de los más importantes son los siguientes:

/dev Contiene ficheros representando los dispositivos físicos del ordenador.
/etc Está reservado para ficheros de configuración del sistema.
/lib Contiene las librerías necesarias para ejecutar los programas que residen en /bin.
/proc Contiene ficheros especiales que reciben información del núcleo.
/sbin Contiene programas que sólo son accesibles para el usuario ‘root’
/usr Contiene los programas de uso común para todos los usuarios y presenta una estructura con directorios /etc, /bin o /lib propios para dichos programas
/var Contiene información temporal sobre la ejecución de algunos programas.
/home Contiene los directorios personales de los usuarios del sistema.

El directorio personal

A diferencia de otros sistemas operativos donde tras inicializar el ordenador el usuario accede por defecto al directorio raíz, en Linux cada usuario lo hace a un directorio personal (home directory) ubicado en algún lugar de la jerarquía de directorios del sistema. A menudo los directorios personales están ubicados debajo del directorio /home.

Directorios especiales

Existe una notación especial para hacer referencia a dos directorios en particular, el directorio actual y el directorio inmediatamente superior al mismo. El primero, se representa mediante un punto(.), mientras que el segundo se indica mediante dos puntos (..)

Rutas absolutas y relativas

Una ruta es el “nombre completo” de un fichero que incluye no sólo su nombre, sino su situación en la jerarquía, separando cada directorio mediante una barra (/). Por defecto, el intérprete asume que los comandos introducidos y los nombres de ficheros y directorios a los que se hace referencia poseen una ruta relativa al directorio actual. Al conectarnos por primera vez, el directorio actual es el directorio personal. Supongamos que acabamos de hacerlo y que es /home/luis. Si escribimos una orden como lista-ficheros-graficos, el intérprete asumirá que la ruta completa del fichero es /home/luis/lista-ficheros-graficos. La idea es que no es necesario indicar toda la ruta, sino sólo el desplazamiento necesario teniendo en cuenta el punto del sistema de ficheros donde estamos situados. También podemos indicar ficheros situados más arriba en la jerarquía. Por ejemplo, si escribimos la orden anterior como ../../bin/lista-ficheros-gráficos, el intérprete buscará el comando dos niveles por encima y luego bajará a bin.

En algunas ocasiones puede ser más conveniente o fácil indicar un nombre completo utilizando una ruta absoluta. Este tipo de rutas comienza siempre por una barra (/) para indicar que la ruta comienza a definirse desde el directorio raíz, independientemente de cuál sea nuestro directorio actual. En el último de los ejemplos anteriores, podríamos especificar la situación del comando como /bin/lista-ficheros-gráficos.

Montaje de unidades de disco

En Linux, a diferencia de otros sistemas, las unidades no se representan con letras (por ejemplo, ‘C:’) sino que se ubican en algún punto de la jerarquía de directorios. La acción de vincular un directorio de la jerarquía a una unidad de disco se denomina montar la unidad.

Si añadimos unidades de disco a nuestro sistema, deberemos montarlas para poder usarlas. Sea un disco duro, un CD, o una unidad USB la instrucción a usar será siempre la misma:

mount [dispositivo] [punto_de_montaje]

Donde dispositivo es el disco que queremos montar y punto_de_montaje el directorio donde queremos montarlo. Los discos duros los encontraremos en /dev/sdXN dónde la X representa el disco (el primero será a, el segundo b, etc.) y N será el número de la partición (en caso de que el disco esté particionado). Así, para montar un segundo disco en el directorio /mnt/discoduro escribiremos:

mount /dev/sdb /mnt/discoduro

El directorio /mnt/discoduro debe existir y estar vacío. Si tiene datos, no estarán disponibles hasta que no se desmonte la unidad, aunque no se perderán.

Para desmontar el disco usaremos la instrucción umount:

umount [dispositivo]

Evidentemente, el disco duro principal sda siempre estará montado, generalmente con varias particiones (sda1, sda2, sda3) . Por otra parte, cuando estemos trabajando con servidores remotos, normalmente no necesitaremos montar ni desmontar unidades.

El interprete de comandos

El intérprete de comandos es programable

Una característica esencial del intérprete de comandos es que no sólo lee e interpreta las órdenes del usuario, sino que también es un lenguaje de programación bastante sencillo de utilizar. Los programas pueden ser tan sencillos cómo un sólo comando con algunas opciones o contener conjuntos de comandos y sentencias de programación del intérprete.

Los programas están diseñados para colaborar

Una idea básica que distingue Linux de otros sistemas operativos es que los programas son herramientas, y como tales, deben tener una función específica pero han de poder usarse para diferentes propósitos. Tres características son necesarias para conseguir esto:

• Los resultados de un programa deben poder usarse como datos de entrada para otros.
• Los programas deben estar preparados para trabajar en modo no interactivo, de forma que todas las opciones y datos que necesitan les puedan venir a través de un fichero.
• Por defecto, los programas deben leer la entrada estándar (el teclado) y mostrar los resultados en la salida estándar (la pantalla).

Cuando los programas pueden usarse de esta forma, es posible indicarle al intérprete que deseamos encadenarlos secuencialmente de forma que la salida de cada uno de ellos constituye la entrada para el siguiente.

Complejidad a la carta

La filosofía de Linux es proporcionar una gran cantidad de utilidades que realizan tareas simples de forma que el usuario básico pueda desenvolverse con comodidad, Pero al mismo tiempo, a través de la combinación de comandos y las capacidades de programación del intérprete, proporciona la posibilidad de crear nuevos comandos más complejos para los usuarios que así lo requieran.

El modo consola

Originalmente la interacción con el intérprete de comandos se realizaba a través de lo que se denominaban consolas (conjunto de teclado y pantalla) introduciendo órdenes en un entorno sin visualización gráfica, únicamente de texto. El intérprete muestra un indicador (prompt) en la línea de comandos para mostrar al usuario que puede introducir una orden. El formato del prompt es muy flexible, pudiendo mostrar información como el nombre del usuario conectado o el directorio actual, por ejemplo.

Actualmente, entornos como XWindow proporcionan interfaces gráficas que evitan muchas de las complejidades de la interacción a través de la consola. Sin embargo, existen todavía comandos (sobre todo de administración del sistema) que no están completamente soportados por aplicaciones gráficas y se hace necesario la interacción a través de lo que denominaremos modo consola o texto en contraste con el modo gráfico.

Sin embargo, en el mantenimiento remoto de servidores Linux, suele ser habitual usar el modo consola. Es conveniente, pues, estar familiarizado con su uso si vamos a tener que trabajar con servidores remotos.

Cuando tengamos que introducir órdenes, debemos tener en cuenta que los intérpretes de comandos de Linux distinguen mayúsculas y minúsculas.

Variables de entorno

Muchas utilidades de Linux, incluyendo el intérprete de comandos, necesitan información sobre el usuario y sus preferencias. Este tipo de información se almacena en las variables de entorno, que son gestionadas por el intérprete de forma que son accesibles a los programas que las necesitan.

Aunque es posible definirlas, existe una serie de variables de entorno predefinidas como por ejemplo las siguientes:

PATH: Contiene la lista de directorios donde el intérprete buscará los comandos que el usuario pida ejecutar.
HOME: Contiene la ruta absoluta hasta el directorio personal del usuario.
PS1: Contiene la definición del prompt principal que muestra el intérprete en modo texto.

La primera interacción

La entrada al sistema

Para poder entrar al sistema, Linux siempre requiere a los usuarios que se identifiquen mediante un nombre y una contraseña para verificar su identidad. Este procedimiento no sólo garantiza la seguridad de acceso al sistema, sino que además permite aplicar los permisos de acceso a la información y de ejecución de programas necesarios para cada usuario.

El usuario root

En Linux existe un usuario especial denominado ‘root’ que es el administrador del sistema y, por tanto, tiene permisos para realizar cualquier acción. Así, puede acceder a los ficheros de todos los usuarios, ejecutar cualquier programa y tiene permisos para acceder a todos los ficheros de configuración del sistema. Por esta razón, no es conveniente trabajar como ‘root’ cuando no se van a realizar tareas de administración, ya que se corre el riesgo de borrar o modificar algo por accidente.

A menudo el usuario root está deshabilitado de manera que no se puede acceder a él. Sin embargo, usuarios con privilegios pueden usar la ordensudo que les permite ejecutar comandos como si fueran el usuario root. Para ello, basta poner sudo delante de la instrucción que se quiera ejecutar. Por ejemplo:

sudo mount /dev/sdb1 /mnt/discoduro

Crear un nuevo usuario

Si necesitamos crear un nuevo usuario la intrucción a usar es adduser. Dado que es una intrucción que necesita privilegios de administración para ejecutarse, usaremos:

sudo adduser [usuario]

El sistema nos pedirá algunos datos del usuario (entre otros su contraseña) y creará el usuario y un directorio para él en /home/usuario

Se puede encontrar más información sobre esta instrucción en: enlace

Primeros comandos

Una vez el usuario ingresa correctamente en el sistema, Linux ejecuta el intérprete de comandos, el cual permanecerá aceptando e interpretando órdenes hasta que finalice la sesión. Algunos comandos que podemos usar en Linux están integrados en el propio intérprete y se denominan comandos internos. Para ejecutarlos, el intérprete no necesita transferir el control a ningún programa externo. El resto de comandos externos deben corresponder a algún programa ubicado en algún punto del sistema y que el intérprete sea capaz de localizar.

Cuando tecleamos un comando, el intérprete mira primero si es interno, en cuyo caso lo ejecuta de inmediato. Si no, hay dos casos posibles: que especifiquemos el comando con una ruta absoluta o simplemente con el nombre. En el primer caso, tampoco hay problema, ya que el intérprete puede localizar con facilidad el programa y ejecutarlo. En el segundo, necesita buscarlo en alguno de los directorios especificados en la variable de entorno PATH.

El prompt

Como ya hemos comentado, el intérprete de comandos muestra el prompt para indicar al usuario que está listo para recibir comandos. El prompt puede tener formatos muy diversos. Habitualmente suele ser usuario@máquina:directorio$ con algunas particularidades. “máquina” puede ser el nombre que tenga la máquina o su IP si no tiene. “directorio” será el directorio actual o ~ si nos encontramos en el nuestro directorio.

Viendo el contenido de un directorio

Si queremos ver el contenido del directorio actual, podemos utilizar el comando ls. Sin embargo, si lo hacemos la primera vez que hemos entrado en la máquina y estamos en nuestro directorio, posiblemente no veamos nada.

En realidad sí que hay archivos en nuestra cuenta, lo que pasa es que están ocultos. Si queremos verlos podemos usar la opción a de la siguiente manera:

ls -a

El resultado será algo parecido a esto:

2.2 1.png Resultado de usar la instrucción ls con la opción a

El archivo en azul no es tal, es un directorio. En este listado tan solo vemos los nombres de los archivos, pero a menudo nos interesará tener más información. Con la opción l obtendremos un listado más completo con información sobre los permisos del archivo, el tamaño en bytes, el propietario del archivo, el grupo al que pertenece, el tamaño y la hora de creación:

2.2 2.png Resultado de usar la instrucción ls con las opciones l y a

Finalmente, si tenemos archivos muy grandes, podemos añadir la opciónh que nos muestra el tamaño en Kb

2.2 3.png Resultado de usar la instrucción ls con las opciones l, a y h

Hay muchas más opciones disponibles que se pueden consultar haciendo ls –help

Que alguien me eche una MANo

Las opciones que hemos visto del comando ls son sólo algunas de las muchas disponibles para este comando. Esto es habitual en muchos otros comandos, por lo que a menudo se hace difícil recordar todas las opciones. Además de la opción –help en Linux es posible obtener ayuda acerca del uso de un comando a través del manual al que se puede acceder a través del comando man seguido del nombre del comando. Así, man ls mostraría el manual de uso de ls, más completo que ls –help Para abandonar la visualización de las páginas del manual, pulsa la tecla ‘q’.

¿Dónde estoy?

Dada la complejidad de la estructura del sistema de ficheros de Linux, siempre cabe la posibilidad de que en algún momento, después de navegar por él, no sepamos exactamente cuál es nuestro directorio actual. Siempre podemos conocerlo a través del comando pwd (print working directory).

Limpiando la pantalla

Para limpiar la pantalla utilizaremos el comando clear.

Finalizar la sesión

Para finalizar la sesión de Linux usaremos la instrucción logout.

¿Da pereza teclear tanto?

Uno de los inconvenientes de la línea de comandos es la necesidad de especificarlo todo con mucho más detalle que, por ejemplo, en una interfaz gráfica. Pueden resultar especialmente complicados la especificación de rutas o ciertos nombres de fichero. Para facilitar la escritura de órdenes, bash ofrece un mecanismo automático de completado de texto mediante el tabulador.

El intérprete intenta completar dependiendo de lo que se haya tecleado, aunque lo más habitual es que primero intente buscar un comando y luego un fichero o directorio. Por ejemplo, supongamos que queremos listar el contenido del directorio /usr/local/bin aprovechando esta característica.

1. Escribimos ‘ls /u’ y pulsamos el tabulador. Automáticamente se completa la ruta como /usr/.
2. Añadimos a la ruta una ‘l’ (/usr/l) y pulsamos el tabulador. Bash hace sonar una señal de aviso para indicar que hay más de una forma posible de completar el texto. Pulsando de nuevo el tabulador nos muestra las tres posibilidades, que son tres directorios que comienzan por ‘l’ debajo de /usr.
3. Tecleamos una ‘o’ haciendo que la ruta quede como /usr/lo y pulsamos el tabulador. Como la ambigüedad ha quedado resuelta, el texto se completa como /usr/local/.
4. Finalmente, escribimos una ‘b’ y pulsamos de nuevo el tabulador. La ruta se vuelve a completar quedando como /usr/local/bin.

Gestión de archivos y directorios

Directorios

Como hemos visto, la estructura del sistema de ficheros de Linux permite ordenar la información en directorios que pueden contener ficheros u otros directorios a su vez. Para poder manipular esta estructura, es necesario disponer de comandos que permitan crear, borrar directorios y moverse a través de ellos.

Cambiar de directorio

Uno de los comandos más utilizados es cd (change directory) que permite cambiar el directorio actual y, de este modo, navegar por el sistema de ficheros. Este comando se usa de la siguiente manera:

cd [camino][directorio]

El camino nos indica la manera de llegar al directorio al que queremos ir. Si está en el directorio donde nos encontrarnos, entonces no hará falta especificar el camino. Antes de verlo con un ejemplo, vamos a ver algunos “directorios” especiales.

Si queremos ir al directorio inmediato superior pondremos .. (dos puntos seguidos)

Si queremos ir al directorio raíz, pondremos / (barra)

Y ahora vemos algunos ejemplos.

Cuando accedemos al sistema, por defecto aparecemos en nuestro directorio, situado en /home/user.

Si queremos ir al directorio superior (/home) escribiremos cd ..

Con el comando pwd podemos comprobar en todo momento donde nos encontramos.

Ahora, si hacemos cd user volveremos de nuevo a nuestro directorio y, desde ahí, si escribimos cd /usr/bin iremos al directorio bin que se encuentra dentro del directorio usr que está en el directorio raíz.

Finalmente, para volver a nuestro directorio, podemos escribir cd sin nada más y nos llevará directamente. La siguiente imagen es una captura de pantalla de un terminal Linux donde hemos realizado las operaciones que acabamos de ver.

3.1.jpg

Captura de pantalla de los ejercicios de práctica con el comando cd

Prueba a navegar por el sistema de ficheros utilizando diferentes métodos para indicar el destino. Si te pierdes, puedes utilizar el comando cd sin parámetros y te devolverá a tu directorio de trabajo.

Crear directorios

El comando mkdir permite crear nuevos directorios.

Eliminar directorios

Se realiza mediante el comando rmdir. Los directorios deben estar vacíos para poder ser eliminados.

Mover y renombrar directorios

Podemos mover un directorio de sitio usando el comando mv de la siguiente manera:

mv [camino]directorioOrigen [camino][directorioDestino]

Es obligatorio poner un origen y un destino. Si se especifica un nombre de directorio de destino, entonces no sólo se mueve, también se le cambia el nombre. Esa característica hace que cambiar el nombre de un directorio sea tan sencillo como hacer:

mv nombreActual nombreNuevo

Los directorios se mueven con todo su contenido.

Los directorios . y ..

Cuando listamos el contenido de un directorio usando la opción a vemos dos directorios (aparecen en azul) con los nombres . y .. Como ya vimos, estos dos directorios son enlaces al directorio actual . y al directorio superior .. (por eso, para ir al directorio superior ponemos cd ..)

El directorio actual (.) es útil, por ejemplo, cuando queremos mover un directorio de un sitio determinado al directorio actual. También cuando copiamos o movemos archivos puede ser útil. Lo vemos cuando hablemos de ficheros.

Ficheros

Copiar ficheros

Para copiar ficheros utilizaremos el comando cp especificando el fichero que deseamos copiar y el lugar donde queremos hacerlo. Se usa de la siguiente manera:

cp [camino]Origen [camino][destino]

Como en el caso de mover directorios, el copiar ficheros necesita obligatoriamente que especifiquemos un destino, sea un camino (si queremos copiar el archivo en otro directorio) sea un nuevo nombre de archivo (si queremos tener una copia del archivo con otro nombre).

Vamos a ver un sencillo ejemplo: Nos encontramos en nuestro directorio y queremos copiar en él un archivo llamado cpuinfo que se encuentra en el directorio /proc Escribiremos:

cp /proc/cpuinfo .

Donde /prog/ es el camino, cpuinfo el nombre del archivo y . el camino del destino. Es importante usar el punto del final que indica nuestro directorio actual, ya que, como hemos dicho, el comando cp necesita obligatoriamente que le indiquemos el destino del fichero, a diferencia de lo que ocurre otros sistemas como por ejemplo MSDOS.

Hay que tener en cuenta que si el nombre de destino ya existe (porque hay un archivo con ese nombre), se sustituirá el existente por la copia que estamos haciendo sin que haya ningún aviso de que vaya a ser así.

Mover y renombrar ficheros

Igual que podíamos mover y renombrar directorios, podemos hacerlo con los ficheros. La instrucción es la misma, funciona de la misma manera.

Nombres de ficheros

Los nombres de archivo en Linux diferencian mayúsculas y minúsculas, pueden contener hasta 255 caracteres y no deberían contener espacios ni caracteres especiales. En realidad pueden contener esos caracteres si el nombre se pone entre comillas, pero no es recomendable. De hecho se aconseja usar tan solo letras (A-Z y a-z), dígitos (0-9), el carácter de subrayado o guión bajo (_) y el punto. No es recomendable usar caracteres acentuados, la eñe ni la ce cedilla (ç)

Ficheros ocultos

Si queremos que un archivo no se liste cuando usamos el comando ls podemos ocultarlo poniendo un punto al principio del nombre. Sin embargo, el archivo se listará si se usa la opción “a”: ls -a

Eliminar ficheros

Finalmente, la eliminación de un fichero se realiza con el comando rm, funciona de la siguiente manera:

rm [camino]archivo

El nombre de archivo es obligatorio.

¡Tocado!

En ocasiones puede ser interesante actualizar la hora de un fichero sin editarlo. Para hacerlo se usa el comando touch poniendo a continuación el nombre del archivo. Este comando también es una manera fácil de crear un nuevo archivo ya que si no existe se crea (vacío, por supuesto).

El comodín *

El asterisco (*) se usa como comodín para indicar un conjunto de archivos. Un solo asterisco indica “todos los archivos” o “todos los directorios”. Así, si escribimos rm * se borraran todos los archivos del directorio actual. Si escribimos rmdir * se borrarán todos los subdirectorios del directorio actual (siempre que estén vacíos). Hay que tener en cuenta que el borrado no pide confirmación y que, por tanto es peligroso usar este comodín de esta manera. También podemos usar el comodín para indicar “todos los archirvos que empiezan por” poniendo, por ejemplo h* o ho*

Entrada y salida

Entrada y salida estándar

Dispositivos de entrada/salida

Para que un usuario pueda comunicarse con el ordenador es necesario disponer de algún dispositivo de entrada que permita introducir órdenes. Asimismo, para que el usuario pueda aprovechar los resultados de las órdenes que ha introducido, necesita que dichos resultados se le muestren de alguna manera.

Estos canales de comunicación se denominan dispositivos de entrada/salida. En Linux los dispositivos por defecto son los denominados entrada estándar y salida estándar. Si un programa lee de la entrada estándar estará obteniendo datos desde el teclado. Cuando escribe algún resultado a la salida estándar, lo estará haciendo a la pantalla.

Ciertos comandos no utilizan la entrada estándar (teclado) para recibir la información que necesitan para ejecutarse, sino que la reciben como argumento directamente.

El interés del concepto de entrada/salida estándar estriba en que todos los dispositivos son tratados como si fueran ficheros. Por esta razón, a los programas no les importa si están leyendo de un teclado o de un fichero ni tampoco si están escribiendo en la pantalla o, de nuevo, en un fichero.

El comando cat

Para ilustrar la noción de entrada/salida estándar, vamos a introducir un comando denominado cat. Este comando toma la información que se le proporciona de entrada, la une y la vuelve a dar como salida.

Por ejemplo, si tecleamos lo siguiente

cat

el sistema quedará aparentemente en espera mostrando una línea en blanco. Si tecleamos una frase y pulsamos Intro, vemos que cat muestra la misma frase por pantalla. Pulsando CTRL-D podemos finalizar la ejecución.

cat
Muestra esta frase
Muestra esta frase

Este ejemplo constituye una demostración del uso de la entrada/salida estándar. La línea en blanco es la forma de indicar que cat está esperando algo del teclado (entrada estándar). Cuando lo tiene, realiza su función que es mostrarlo por pantalla (salida estándar).

Redirección de la entrada/salida

Redirección de la salida

La manera que hemos visto de utilizar el comando cat no parece demasiado útil. Pero, ¿y si en lugar de escribir lo que introducimos por teclado en la pantalla lo pudiéramos escribir en un fichero? Para ello podemos utilizar los mecanismos de redirección de la salida que proporciona Linux, que permiten cambiar el dispositivo de salida estándar.

Para redirigir la salida estándar utilizaremos el símbolo ‘>’ seguido de un nombre de fichero. Como ejemplo, podemos introducir el comando cat como sigue y los textos que se muestran:

cat > telefonos.txt
Luis Terreros 5553251
Mateo Guerricer 5559082
Gema Pellon 5558727
Luis Terico 5550255
Carlos Calzado 5550178

Tras finalizar la ejecución con CTRL-D, podemos introducir el comando ls para comprobar que, efectivamente, se ha creado un fichero llamado telefonos.txt. La redirección le ha indicado al comando cat que escriba la salida en este fichero en lugar de hacerlo en pantalla. Como resultado, el fichero contendrá el listado que hemos introducido. Para comprobarlo, podemos utilizar el mismo comando cat de la siguiente forma:

cat telefonos.txt
Luis Terreros 5553251
Mateo Guerricer 5559082
Gemma Pellon 5558727
Luis Terico 5550255
Carlos Calzado 5550178

Como vemos el comando cat puede utilizarse de manera que tome como argumento un fichero a visualizar en lugar de la entrada estándar.

El método de redirección que hemos visto siempre crea un fichero nuevo para recoger la salida y, en caso de que ya exista uno con el mismo nombre, lo borra primero. Si necesitamos redirigir la salida hacia un fichero ya existente sin borrar su contenido, podemos usar el símbolo ‘>>’ para indicar que la redirección debe hacerse añadiendo el nuevo resultado detrás del contenido existente.

Redirección de la entrada

De forma similar a como se ha visto para la salida estándar, es posible redireccionar también la entrada utilizando el símbolo ‘<‘. Por ejemplo, podríamos proporcionarle al comando cat el contenido del fichero telefonos.txt como entrada de la siguiente manera:

cat < telefonos.txt

Aunque hemos visto que no es necesario ya que este comando puede aceptar como argumento un nombre de fichero, hay otros comandos que sólo están diseñados para leer y escribir en los dispositivos estándar. Un ejemplo es el comando tr que permite transformar cadenas de texto de diversas formas. Si queremos cambiar todas los caracteres del texto de telefonos.txt de minúsculas a mayúsculas podemos hacer lo siguiente:

tr [:lower:] [:upper:] < telefonos.txt
LUIS TERREROS 5553251
MATEO GUERRICER 5559082
GEMA PELLON 5558727
LUIS TERICO 5550255
CARLOS CALZADO 5550178

El texto entre comillas es un argumento del comando tr que simplemente le indica que convierta las minúsculas en mayúsculas.

Finalmente, podemos ilustrar la utilización combinada de ambas formas de redirección completando el ejemplo anterior para que deje su salida en un fichero llamado telef-may.txt:

tr [:lower:] [:upper:] < telefonos.txt > telef-may.txt

Tuberías (pipes)

Quizás la utilidad más potente de la entrada/salida estándar es la posibilidad de encadenar comandos a través del uso de “tuberías” (pipes), que permiten que la salida de un comando sirva como entrada a otro.

Por ejemplo, si queremos ver el contenido del directorio /usr/bin podemos utilizar el comando ls como sigue:

ls /usr/bin

El problema es que este directorio contiene demasiados ficheros y éstos desaparecen de la pantalla muy rápidamente al visualizarlos. Para solucionarlo, sería útil tener alguna forma de visualizar textos que dividiera la visualización en páginas a través de las cuales pudiéramos navegar con mayor comodidad.

El comando more realiza una función como la que hemos descrito. Así, si deseamos visualizar página a página el contenido de un fichero llamado HOWTOUSE con información sobre el uso del programa cdda2wav situado en el directorio /usr/share/doc/cdda2wav, podemos hacer lo siguiente:

more /usr/share/doc/zip-3.0/README

El comando visualiza el contenido del fichero pero deteniéndose cuando el texto ocupa toda la página e indicando con un texto en la parte inferior el porcentaje del total que se ha mostrado hasta el momento. Pulsando la barra espaciadora podemos ir viendo el resto de páginas y pulsando la tecla ‘q’ finalizar la visualización.

Aunque el comando more parece adecuado para el problema que planteamos antes, la cuestión es ¿cómo lo aplicamos al resultado de visualizar el contenido de un directorio con ls si necesita que le proporcionemos un fichero como argumento? La solución consiste en encadenar la salida del comando ls y usarla como entrada para el comando more a través de una “tubería”. Para ello utilizaremos el símbolo ‘|’ de la siguiente forma:

ls /usr/bin | more

Como resultado, obtenemos la salida que proporciona ls pero dividida en páginas.

Con el comando less puedes hacer lo mismo que con more, pero con la ventaja de que puedes avanzar y retroceder en el archivo. Prueba a repetir los ejemplos aquí usados, cambiando more por less.

Permisos

El sistema de seguridad de archivos

En un sistema multiusuario como Linux es muy importante establecer mecanismos de seguridad de los ficheros para controlar quién puede acceder a ellos y que tipos de acceso puede llevar a cabo. Por ejemplo, si intentamos eliminar el directorio personal del usuario ‘ec2-user’ obtendremos un mensaje de error:

$ rmdir /home/ec2-user
rmdir: failed to remove '/home/root': Permision denied

Evidentemente sería muy arriesgado permitir que cualquier usuario pudiera realizar una acción que perjudicara al funcionamiento del sistema o al trabajo de otros usuarios. Pero el sistema de seguridad también tiene que tener en cuenta la organización de los usuarios en grupos de Linux que permite compartir ficheros y directorios entre distintos usuarios. Seguidamente veremos los mecanismos que ofrece el sistema para solucionar estos aspectos.

Tipos de permisos

El sistema de permisos de Linux que se aplica a cada fichero o directorio divide los usuarios en tres categorías:

Propietario: Usuario que creó el fichero (aunque puede ser otro si ha sido modificado por algún usuario con los privilegios suficientes).
Grupo al que pertenece el fichero (inicialmente el del propietario).
Otros: resto de usuarios distintos del propietario y los miembros de su grupo.

Para cada fichero y cada una de estas categorías, es posible establecer tres tipos de permisos:

Lectura: Para un fichero determina si podemos visualizarlo. Para un directorio, si podemos visualizar su contenido.
Escritura: Para un fichero determina si podemos modificarlo, eliminarlo o cambiarlo de nombre. Para un directorio indica lo mismo pero afecta también a su contenido.
Ejecución: Para un fichero determina si podemos ejecutarlo. Para un directorio, indica si podemos entrar en él y ejecutar su contenido.

El conjunto de todas las combinaciones posibles forma lo que denominamos la máscara de permisos de un fichero como muestra la siguiente figura:

5.1.gif

Para visualizar el conjunto de permisos de un fichero podemos utilizar el comando ls con la opción -l. Por ejemplo, veamos los permisos del directorio personal del usuario ‘ec2-user’ (añadimos también la opción d para listar el directorio y no el contenido del directorio):

$ ls -ld /home/ec2-user
drwx------ 3 ec2-user ec2-user 4096 2003-01-26 02:05 /home/ec2-user

La primera cadena de caracteres contiene el tipo de fichero (la ‘d’ indica que es un directorio) y los permisos actuales. Cuando aparece un guión, significa que el permiso no está activado. Seguidamente se indica el tamaño, el propietario y el grupo al que pertenece. Como vemos, sólo el propietario tiene permisos de escritura, que son los que nos permitirían eliminar el directorio. Como el propietario es ‘ec2-user’, sólo este usuario puede hacerlo.

Gestión de permisos

Modificación de permisos

Para modificar los permisos de un fichero o directorio se utiliza el comando chmod. Utilizaremos las letras ‘u’, ‘g’ y ‘o’ para representar a las categorías de propietario, grupo y otros, respectivamente. Para indicar los permisos activados o desactivados, usaremos las letras r, w y x para lectura, escritura y ejecución. Finalmente, usaremos tres operadores ‘+’, ‘-‘ y ‘=’, para hacer que los permisos se añadan a los existentes, se quiten de los que ya había o sean los únicos aplicables, respectivamente. Por ejemplo, la siguiente secuencia de comandos crea un nuevo directorio llamado temporal y modifica sus permisos para que el propietario pueda leer, escribir y ejecutar, los otros miembros del grupo puedan leer y los demás no tengan ningún permiso. Los comandos ls permiten ver que se ha realizado la modificación.

$ mkdir temporal
$ ls -ld temporal
drwxrwxr-x 2 user user 0 2013-01-26 02:05 temporal
$ chmod u=rwx,g=r,o= temporal
$ ls -ld temporal
drwxr----- 2 user user 0 2013-01-26 02:05 temporal

Podemos ver otro ejemplo de uso con un operador distinto añadiendo permisos de ejecución al grupo y de lectura al resto de usuarios:

$ chmod g+x,u+r temporal
$ ls -ld temporal
drwxr-xr-- 2 user user 0 2013-01-26 02:05 temporal

Al usar el comando ls para listar un directorio en concreto, debemos usar la opción -d para listar sus propiedades en lugar de las correspondientes a los ficheros que contiene.

También podemos definir los permisos usando un número de tres dígitos de manera que el primer dígito se refiere al usuario, el segundo al grupo y el tercero a todos. A su vez cada dígito puede tener un valor del 0 al 8 con los siguientes criterios (atención a la codificación binaria):

- – - = 0 no se tiene ningún permiso
- – x = 1 solo permiso de ejecución
- w - = 2 solo permiso de escritura
- w x = 3 permisos de escritura y ejecución
r – - = 4 solo permiso de lectura
r – x = 5 permisos de lectura y ejecución
r w - = 6 permisos de lectura y escritura
r w x = 7 todos los permisos establecidos, lectura, escritura y ejecución

Así, si tenemos la instrucción

chmod 700 directorio

Le estamos dando todos los permisos al usuario pero ninguno a los demás. Y

chmod 766 directorio

Da permiso total al propietario, y de lectura y escritura (que no de ejecución) al resto de usuarios.

Nuevos propietarios

En algunos casos es necesario asignar a un fichero un propietario distinto al que lo ha creado. Por ejemplo, el administrador del sistema puede añadir ficheros de configuración a los directorios de un usuario y luego hacer que éste último sea el propietario para permitir que los modifique a su gusto.

Para realizar este cambio, disponemos del comando chown. Este comando admite como parámetros un nuevo propietario y, opcionalmente y separado por un punto, un nuevo grupo. Por ejemplo, la siguiente secuencia de comandos copia un fichero al directorio personal del usuario ‘user’ para luego asignarle este mismo usuario como propietario así como también el grupo ‘user’.

$ sudo cp /usr/share/info/dir /home/user
$ cd /home/user
$ ls -l dir
-rw-r–r– 2 root root 13678 Feb 25 02:05 dir
$ chown user:user dir
$ ls -l dir
-rw-r–r– 2 knoppix knoppix 0 2003-01-26 02:05 a2ps.html

Siguiendo las indicaciones que hemos visto con anterioridad, crea un nuevo usuario, asígnale una contraseña e intenta probar las posibilidades de acceso a los ficheros y directorios del usuario ‘user’ utilizando diferentes combinaciones de permisos.

Sugerencia: Puedes utilizar desde un terminal la orden su seguida del nombre del usuario para comenzar una sesión con el nuevo usuario sin tener que pasar al modo texto. Por ejemplo, ‘su luis‘ inicia una sesión con el usuario ‘luis’ después de solicitar la contraseña para el mismo.

Edición de texto

vi /vim

Linux proporciona una amplia variedad de aplicaciones de edición de texto de muy diversos tipos y diferentes niveles de prestaciones, de forma que es una cuestión de gustos o necesidades más o menos avanzadas elegir entre una u otra. La razón para conocer el editor vi es que se encuentra virtualmente en todas las distribuciones de Linux y funciona en modo texto. Así, aunque podamos preferir un editor de otro tipo en el uso diario, puede haber ciertas ocasiones en las que resulte útil saber utilizarlo al menos a nivel básico, como por ejemplo situaciones en las que no es posible acceder al entorno gráfico o en accesos remotos al sistema con disponibilidad limitada de aplicaciones.

Arrancando vi

Para arrancar vi simplemente hemos de escribir el comando desde un terminal. Si le proporcionamos un nombre de fichero como parámetro, abrirá dicho fichero, si no, abrirá uno nuevo. Entremos, por ejemplo

$ vi prueba.txt

Se abrirá el programa, que ocupa toda la pantalla, sitúa el cursor arriba a la izquierda y llena la mayor parte de líneas con el carácter ‘~’ indicando que no contienen texto. En la parte inferior se encuentra el área de estado y de comandos que, en este momento, indica que hemos abierto un fichero nuevo llamado prueba.txt.

El editor ofrece dos modos de funcionamiento, el modo de edición y el modo comando. El primero es el que permite realizar todas las tareas posibles de edición, es decir, inserción, modificación o eliminación y considera cada tecla como texto a incluir. El segundo, en cambio, interpreta lo que tecleamos como parte de un comando y no lo incluye en el texto sino que lleva a cabo una acción (por ejemplo, guardar el fichero).

Mi primer texto

Al arrancar, vi se encuentra en modo comando, por lo que habrá que proporcionarle alguno para pasar al modo de edición, como por ejemplo insert. Para ello pulsamos una i y a partir de ese instante el texto que entramos se incluye en el fichero. Puedes observar como la línea de estado de vi indica que estamos en modo de inserción (‘–INSERT–‘). Mientras editamos podemos movernos a través del texto con las flechas del teclado e insertar nuevas líneas con la tecla intro. Introduce el texto ‘Al principio cuesta un poco acostumbrarse a vi, pero puede llegar a ser un editor muy potente.’.

Una vez hemos entrado el texto, tendremos que grabarlo mediante el comando correspondiente. Para pasar al modo comando utilizaremos la tecla ESC. Al pulsarla, vemos como cambia la línea de estado dejando de indicar el modo anterior. Ahora podemos introducir un comando. Concretamente, para guardar los cambios en el fichero utilizaremos ‘w‘. La línea de estado indicará que el texto se ha grabado correctamente:

6.1.png

Para salir utilizaremos el comando ‘q‘, que nos devolverá a la línea de comandos del terminal. Otros comandos útiles son los siguientes:

• ‘q!‘ para salir sin guardar los últimos cambios.
• ‘wq‘ para guardar los cambios y salir.
• ‘r‘ seguido del nombre de un fichero para insertar el contenido de otro fichero.

Al principio es normal que a veces no sepamos en que modo estamos e intentemos editar cuando estamos en modo comando sin resultados. Si no estamos seguros, lo más conveniente es pulsar ESC para estar seguro de pasar a modo comando y así entrar fácilmente al modo de edición.

Modificación de texto

Aunque versiones modernas de vi permiten eliminar texto utilizando las teclas de borrado habituales, podemos encontrarnos en situaciones donde la terminal no esté configurada para ello. En estos casos, es útil conocer algunos comandos que realizan estas funciones.

Vamos a volver a editar el texto anterior entrando el comando ‘vi prueba.txt‘. Ahora realizaremos los siguientes pasos para ver un ejemplo de uso de comandos para la eliminación de texto:

1. Introduce el comando ‘i‘ para entrar en modo de edición.
2. Sitúate sobre la letra ‘u’ de ‘un poco’ y pulsa la tecla ESC para pasar a modo comando.
3. Pulsa ‘x‘ varias veces hasta borrar ‘un poco’. Verás como se van eliminando caracteres hacia la derecha.
4. Entra ‘A‘ para colocarte en modo de edición al final de la línea.
5. Pulsa la tecla intro para pasar a una línea nueva e introduce el texto ‘Esta línea no sirve’.
6. Vuelve a pulsar ESC para pasar al modo comando y entra ‘dd‘ para borrar la línea completa.

Igualmente, aunque para desplazarnos podemos utilizar las flechas del teclado, si ello no fuera posible disponemos también de los siguientes comandos:

‘j’ mover el cursor hacia abajo.
‘k’ mover el cursor hacia arriba.
‘h’ mover el cursor hacia la izquierda
‘l’ mover el cursor hacia la derecha

Si quieres repetir el último comando puedes entrar simplemente un punto ‘.’ y se volverá a ejecutar. Si en cambio, quieres deshacerlo puedes usar el comando ‘u’.

Algunos comandos útiles

Búsqueda de texto

No encuentro las cosas

Supongamos que queremos buscar un comando en nuestro sistema que se llama python (en este caso es un intérprete de python). Si conocemos su ubicación exacta, en este caso /usr/bin, es fácil listar los ficheros que cumplen nuestras restricciones usando el comando ls:

$ ls /usr/bin/python*

El problema es que los comandos de Linux se pueden distribuir por muchos directorios distintos y a veces no sabemos exactamente dónde están.

Find

El comando find es uno de los más importantes de Linux. Permite encontrar ficheros y directorios que encajan con una especificación dada que puede incluir desde el nombre, hasta fechas de modificación o los permisos que tiene asignados.

De forma intuitiva, podemos especificar el uso de este comando de la siguiente forma:

find <dónde comenzar la búsqueda> <criterio de búsqueda> <acciones a realizar>

En el ejemplo anterior, podemos utilizar el comando find indicando que busque en todo el directorio /usr de la siguiente forma:

$ find /usr -name python* -print
/usr/include/python2.6
/usr/share/doc/python-lockfile-0.8
/usr/share/doc/python-markdown-2.0.1
/usr/share/doc/m2crypto-0.20.2/demo/Zope/lib/python
...

En el ejemplo vemos el uso típico del comando. Primero indicamos que la búsqueda comience a partir del directorio /usr. Automáticamente find buscara también en todos los subdirectorios contenidos en el mismo. Seguidamente le proporcionamos un criterio de búsqueda mediante el parámetro -name, que indica el nombre de los ficheros a buscar. Finalmente le especificamos que la acción a realizar es mostrar los resultados en pantalla mediante el parámetro -print.

El resultado que se muestra no sólo nos indica los nombres de los comandos, sino también nos ofrece información sobre otros ficheros relacionados y entradas del manual.

Aunque en muchas versiones modernas de find el parámetro -print se asume por defecto, es conveniente acostumbrarse a usarlo por si debemos trabajar con versiones más antiguas en las que podríamos no obtener ninguna salida por pantalla.

El tiempo es oro

El comando find permite realizar búsquedas teniendo en cuenta las fechas de acceso o modificación de los ficheros, lo cual resulta muy útil para encontrar ficheros muy antiguos o los últimos en los que hemos realizado modificaciones, por ejemplo.

El siguiente comando busca los ficheros de nuestro directorio que se han modificado entre la fecha actual y dos días atrás utilizando la opción -mtime:

$ find /home/user -mtime -2 -print

Otras opciones disponibles son las siguientes:

-atime n	Busca ficheros que tuvieron accesos hace n días.
-ctime n	Busca ficheros cuyos atributos (por ejemplo, permisos) se modificaron hace n días.
-amin n	Similar a -atime pero con accesos de hace n minutos.
-cmin n	Similar a -ctime pero con modificaciones de hace n minutos.

El tamaño importa y el tiempo también

En la actualidad, es muy fácil llenar el disco duro instalando aplicaciones que ocupan grandes cantidades de espacio o bajando de Internet ficheros multimedia de tamaño elevado, por ejemplo. Por ello puede resultar útil poder encontrar ficheros que ocupan un cierto tamaño en el disco. La opción -size del comando find permite realizar una búsqueda de este tipo. Tras dicha opción, debemos especificar el tamaño, por defecto en bloques de 512 bytes (0.5Kb), añadiendo una k, en Kbytes o añadiendo una M en Mbytes. Asimismo podemos indicar que queremos encontrar los ficheros con tamaño igual o mayor al indicado añadiendo un `+’. Por ejemplo, el comando siguiente busca los ficheros mayores de 500 Kb en el directorio /usr/bin:

$ find /usr/bin -size +500k -print

Por otro lado, hasta ahora hemos dejado que find encuentre todo tipo de ficheros, incluyendo por ejemplo directorios. Pero es posible especificar con más detalle el tipo que queremos buscar con la opción -type, seguida de una letra, como vemos en el siguiente ejemplo en que restringe una búsqueda anterior únicamente a ficheros normales usando la letra ‘f':

$ find /home/user -mtime -2 -type f -print

Otras opciones serían ‘d’ para directorios o ‘l’ para enlaces.

La hora de la ejecución

Ya hemos visto la gran flexibilidad que proporciona find a la hora de establecer criterios de búsqueda. Seguidamente, veremos cómo resulta una potente herramienta gracias a la posibilidad de ejecutar comandos sobre los resultados de la búsqueda.

Imaginemos que queremos realizar una copia de todos los ficheros de nuestro directorio de trabajo modificados como mucho hace dos días a un directorio de otro usuario llamado prueba. En el ejemplo anterior hemos visto que para encontrarlos podemos utilizar las opciones -mtime y -type del comando find. Pero ¿cómo podemos especificar que queremos realizar una acción de copia sobre ellos? La solución consiste en utilizar la opción -exec seguida del comando a ejecutar. En este caso el comando es cp y necesita saber el fichero a copiar y el destino. Este último es el directorio /home/prueba, pero no hay un sólo fichero a copiar sino una lista de la cual no sabemos los nombres hasta ejecutar el comando. Para solucionar este último problema, podemos utilizar los símbolos ‘{}’, que representan cada uno de los resultados proporcionados por find. Así, si escribimos ‘cp {} /home/prueba‘ significa ‘copia cada fichero resultante al directorio /home/prueba‘. Veamos la solución final:

$ find /home/user -mtime -2 -type f -exec cp {} /home/prueba \;

Las posibilidades de uso de esta opción son muy amplias siendo especialmente útil para automatizar tareas que se deben realizar sobre grupos de ficheros que cumplan ciertas características.

Prueba a utilizar la opción -exec con el comando rm para borrar los ficheros que has incluido en el directorio creado anteriormente. Ten cuidado, ya que puedes perder ficheros accidentalmente.

Búsqueda dentro de textos

Grep

Ya hemos visto como podemos realizar búsquedas de ficheros con una amplia variedad de opciones. Sin embargo, a menudo es necesario también buscar dentro de un fichero (normalmente en ficheros de texto). Para ello podemos utilizar el comando grep.

Informalmente, podemos ver el uso del comando de la siguiente forma:

grep <opciones de búsqueda> <cadena de texto a buscar> <ficheros>

Las opciones son optativas y aunque la especificación de la cadena de texto a buscar admite descripciones muy complejas es posible utilizar grep de forma tan sencilla como sigue:

$ grep Calzado telefonos.txt
Carlos Calzado 5550178

En este ejemplo hemos buscado la cadena “Calzado” en el listado de teléfonos que hicimos en un ejercicio anterior y grep nos devuelve la línea del texto donde la encuentra. Esto puede resultar de gran utilidad si manejamos un fichero con un gran volumen de información.

Podemos incluir más de un fichero en la búsqueda, como en el siguiente ejemplo:

$ grep Calzado telefonos.txt telef-may.txt
telefonos.txt:Carlos Calzado 5550178

Vemos que ahora la salida incluye el nombre del fichero donde se ha encontrado la cadena. Es interesante también comprobar que no la ha encontrado en el segundo fichero. La razón es que este último contiene los nombres en mayúsculas. Para indicarle al comando que no nos importa si la cadena está en mayúsculas o minúsculas podemos usar la opción -i como sigue:

$ grep -i Calzado telefonos.txt telef-may.txt
telefonos.txt:Carlos Calzado 5550178
telef-may.txt:CARLOS CALZADO 5550178

A veces puede interesarnos simplemente saber en cuántas líneas de un fichero se encuentra la cadena. Para ello podemos usar la opción -c combinada con la anterior:

$ grep -ic Luis telefonos.txt telef-may.txt
telefonos.txt:2
telef-may.txt:2

Asimismo podemos también buscar líneas que no contengan una cadena. Siguiendo el ejemplo anterior, podemos buscar las líneas que no contienen ‘Luis’ usando la opción -v:

$ grep -iv Luis telef.may.txt
MATEO GUERRICER 5559082
GEMA PELLON 5558727
CARLOS CALZADO 5550178

Entubando greps

La utilidad del comando grep se muestra especialmente cuando se combina con otros comandos. Como hemos visto con anterioridad una forma de hacerlo es usando ‘tuberías’. Para ello hay que recordar los conceptos de entrada y salida estándar que vimos y considerar que la salida de un comando puede verse como un fichero.

Por ejemplo, si listamos utilizando la opción -l los ficheros del directorio /var/log/ que guarda registros de actividad del sistema obtendremos una salida como la siguiente:

$ ls -l /var/log
total 5176
drwxr-x--- 2 root root 4096 Feb 18 17:16 audit
-rw------- 1 root root 972 Mar 26 2012 boot.log
-rw------- 1 root utmp 2198784 Feb 22 06:12 btmp
-rw------- 1 root utmp 2688 Apr 18 2012 btmp-20130208
...

Supongamos que nos interesan sólo los ficheros normales (no directorios) y del grupo ‘utmp’. Si vemos esta salida como un fichero, la solución podría ser utilizar el comando grep especificando que busque la cadena ‘utmp’ y que compruebe que no hay una ‘d’ al principio de la línea.

Comenzando por la primera condición, escribiremos lo siguiente:

$ ls -l /var/log | grep utmp

El resultado es el conjunto de líneas del listado que contienen ‘utmp’. Utilizando el símbolo ‘|’, como habíamos visto, redireccionamos la salida del primer comando al segundo. Ahora podemos añadir otro comando grep para especificar la segunda condición:

$ ls -l /var/log | grep utmp| grep -v ^d

El símbolo ‘^’ antes de la cadena a buscar indica que debe estar situada al principio de la línea, que es exactamente lo que nos interesa. Como resultado tenemos el listado resultante del encadenamiento anterior, pero sin directorios.

Finalmente, podemos ilustrar la utilidad de la redirección para resultados demasiado largos para ver en pantalla o que deseamos conservar:

$ ls -l /var/log | grep utmp| grep -v ^d > lista-adm.txt
Ten en cuenta que no se especifica ninguna opción para la posición de la cadena ‘utmp’, por lo que grep puede devolver no sólo los ficheros de dicho grupo, sino cualquier línea del listado que contenga el texto.
Prueba a combinar el comando find y el comando grep para buscar cadenas de texto dentro de un listado de ficheros que cumplen unos criterios de búsqueda.

Ayuda a la edición

cut

Supongamos que queremos saber cuántas personas de nuestro listado de teléfonos se apellidan ‘Luis’. Podemos utilizar el comando grep como hemos visto con anterioridad para seleccionar las líneas que contienen esta cadena, pero como resultado obtendremos todas las apariciones de ‘Luis’ del listado, no sólo los apellidos.

Para reproducir este ejemplo, copia el fichero telefonos.txt a otro fichero en el mismo directorio llamado telefonos2.txt. Utiliza vi para modificar la entrada correspondiente a ‘Mateo Guerricer’ como ‘Mateo Luis’.

$ grep Luis telefonos2.txt
Luis Terreros 5553251
Mateo Luis 5559082
Luis Terico 5550255

Sería muy útil poder filtrar el contenido del fichero de forma que únicamente nos proporcionara los apellidos. O dicho de otra forma, que pudiéramos obtener únicamente la segunda columna.

El comando cut nos permite realizar este tipo de funciones. Este comando divide cada línea en columnas a partir de un separador dado mediante la opción -d. Combinada con la opción -f seguida del número de columna, podemos obtener el resultado deseado.

$ cut -d" " -f2 telefonos2.txt
Terreros
Luis
Pellon
Terico
Calzado

En este ejemplo hemos especificado entre comillas un espacio como separador y obtenido la segunda columna. Ahora, sólo queda conectar esta salida con grep y la opción de contar apariciones:

$ cut -d" " -f2 telefonos2.txt | grep -c Luis
1

tr

Este comando es un filtro “traductor” que lee caracteres de la entrada estándar y elimina o sustituye los que cumplen un cierto patrón. El esquema de uso general es el siguiente:

tr <modificación>
Para reproducir el siguiente ejemplo, utiliza vi para añadir al final de cada entrada de la lista contenida en telefonos2.txt las siguientes fechas de nacimiento con el mismo formato y orden:
08-02-1970
04-08-1964
06-09-1972
09-06-1968
12-07-1968

Imaginemos que queremos incluir estos datos en una base de datos que requiere que el formato de las fechas utilice el separador ‘/’ en lugar del guión. Podemos utilizar el comando tr para hacerlo de la siguiente forma:

$ tr "-" "/" < telefonos2.txt

Es importante fijarse en que la entrada de este comando no se puede especificar como parámetro sino que debe venir por la entrada estándar, por lo que hemos tenido que utilizar la redirección para utilizarlo.

El comando tr permite especificar grupos de caracteres durante la sustitución. En ejemplos anteriores hemos visto el uso de [:upper:] y [:lower:] para representar mayúsculas y minúsculas respectivamente. Siguiendo con el ejemplo anterior, podemos suponer que existe otro requerimiento que nos obliga a separar las columnas con comas en lugar de blancos. Para solucionarlo podemos hacer lo siguiente:

$ tr [:blank:] "," < telefonos2.txt

Aquí usamos [:blank:] para indicar cualquier espacio en blanco o tabulador. Los resultados de todos estos ejemplos se muestran por pantalla, pero es posible redireccionarlos a su vez a un fichero.

Compresión y archivo

A empaquetar

Las utilidades de archivo sirven para “empaquetar” juntos un conjunto de ficheros en un único fichero nuevo. En Windows estas funciones se pueden realizar mediante programas como PKZip (o WinZip) , que además de crear un archivo de ficheros pueden comprimirlo.

Para realizar funciones de archivo en Linux disponemos del comando tar. Las primeras versiones del comando no realizaban funciones de compresión, pero se han añadido en versiones posteriores. Para crear un archivo de ficheros se debe usar la opción -c. Para indicar el fichero de archivo (el que contendrá a los demás) se utiliza la opción -f seguida de un nombre. El siguiente ejemplo crea un archivo llamado midirectorio.tar con todos los archivos con extensión ‘.txt’ de nuestro directorio actual:

$ tar -cf midirectorio.tar *.txt

Si queremos que además de crear el archivo lo comprima, añadiremos la opción -z:

$ tar -czf midirectorio.tar *.txt

Para descomprimir los ficheros contenidos en un archivo, se usa la opción -x. Igual que antes, debemos usar la opción -f seguida de un nombre de fichero para indicar que fichero deseamos descomprimir. Añadiremos también la opción -z para informar que el archivo se creó comprimido:

$ tar -xzf midirectorio.tar

En cualquiera de estos casos se puede añadir -v para que el comando muestre información mientras se ejecuta.

Si al comando tar le pasamos como parámetro el nombre de un directorio, agrupará todo el árbol de directorios por debajo de él y su contenido de forma que, al descomprimirlo, podremos recuperar exactamente la misma estructura. Pruébalo con diferentes directorios para ver como funciona.

Compresión

Independientemente del comando anterior, Linux ofrece otro comando para comprimir ficheros uno a uno, gzip. Para utilizarlo simplemente hay que escribir el comando seguido de su nombre. Por ejemplo, la siguiente orden comprime el fichero telefonos.txt:

$ gzip telefonos.txt

El comando le añade la extensión ‘.gz’ para indicar que es un fichero comprimido (telefonos.txt.gz). Para descomprimirlo usaremos el mismo comando con la opción -d:

$ gzip -d telefonos.txt.gz

zip y unzip

zip

En Linux también podemos comprimir y descomprimir archivos .zip. Para comprimir podemos usar el comando zip de la siguiente manera:

zip -<opciones> <archivo comprimido> <lista de archivos a comprimir>

Así, podríamos hacer:

$zip telefonos telefonos.txt telefonos2.txt

Y nos crearía un archivo telefonos.zip que contendría los dos archivos de texto comprimidos.

Con la opción ‘r‘ podemos comprimir un directorio entero. Es interesante ver el contenido de man para el comando zip para ver todas sus posibilidades.

unzip

Igual que podemos comprimir con zip, podemos descomprimir con unzip. El comando se usa de la siguiente manera:

unzip -<opciones> <archivo comprimido> [<lista de archivos a descomprimir>]

Por defecto, y acostumbrará a ser la opción más usada, si no se ponen opciones ni lista de archivos a descomprimir, se descomprimirá todo el archivo, conservando, si lo hubiese, el árbol de directorios.

Enlaces a materiales de referencia

Os pedirá el primer apellido y el DNI (20+DNI) para poder acceder. Es posible que la primera vez no os permita bajar correctamente el archivo que queráis, volver a atrás y volver a entrar soluciona el problema...



Instalando aplicaciones en CentOS

Manuales oficiales