Utilidades GNU

ArticleCategory:[Categoría del Artículo]

UNIX Basics

AuthorImage:[Fotografía del Autor]

[Foto del Autor]

TranslationInfo:[Historia de traducción]

original in es Manuel Muriel Cordero

AboutTheAuthor:[Sobre el Autor]

Manuel Muriel Cordero es estudiante de la Facultad de informática y estadística de Sevilla.

Abstract:[Resumen]

ArticleIllustration:[Ilustraci'on de Cabecera]

[Ilustracion]

ArticleBody:[Contenido del Articulo]

En el articulo anterior de esta serie se dio un repaso a los aspectos más generales de Linux. Con él se introdujo al lector en los asuntos mínimos para entablar un uso manejable sobre el sistema operativo. El usuario puede desear conocer herramientas típicas de los Unix , y por extensión Linux, para poder controlar la administración de archivos de forma más eficiente. En este artículo se pretende explicar un conjunto de herramientas un poco más avanzadas pero básicas para esa función.

Introducción. El método de trabajo de Unix.

Antes de empezar a detallarlas el lector debe conocer un poco el porque de sus peculiaridades. Kem Thompsom y Denis Ritchie cuando crearón Unix a principios de los sesenta tuvieron en mente crear un sistema operativo que facilitase la labor a los programadores. A la conclusión que llegaron es que la mejor forma es establecer un conjunto definido de pequeñas herramientas que hagan una determinada labor muy bien. A partir de la unión de esas herramientas se pueden realizar labores más complejas mediante la comunicación de los resultados de unas se conviertan en entradas de otra.

Esa forma de trasmitirse la información se realiza con el uso de la entrada y salida estandar ( pantalla y teclado ). Pero gracias a la existencia de las tuberias y redireciones ( que vimos en el capítulo anterior ) se consiguen esos resultados.

Se puede apreciar en un ejemplo. Si un usuario introduce esta linea:

$ who | grep pepe

who y grep son programas distintos separados por la tubería "|" . who nos muestra un listado de todos los usuarios conectados al ordenador en el momento dado. Su salida habitual sería algo parecido a esto:

$ who
manolo	tty1	Dec 22	13:15
pepe	ps/2	Dec 22	14:36
root	tty2	Dec 22	10:03
pepe	ps/2	Dec 22	14:37

Lo que devuelve who se divide en 4 campos separados por tabuladores. Los cuales son nombre de usuario (login) , terminal en el que esta conectado , fecha y hora de inicio de la conexión.

"grep pepe" por su parte busca las lineas de esa salida que contengan la secuencia "pepe".

De esta forma la salida es:

$ who | grep pepe
pepe	ps/2	Dec 22	14:36
pepe	ps/2	Dec 22	14:37

Por ejemplo si ahora el usuario en cambio quiere algo más simple, es decir saber si está o no está conectado mediante el número de conexiones que tiene en este momento se debe usar la utilidad wc.

wc es contador de letras,palabras y lineas. En este caso solo precisamos saber el número de lineas así que se ha de utilizar la opción -l

$ who | grep pepe | wc -l
	2

pepe esta conectado en 2 terminales

Si ahora probamos con antonio

$ who | grep antonio | wc -l
	0

antonio no esta conectado

Origen de Las utilidades GNU

Richar Stallman , fundador del proyecto GNU, observó que es éticamente discutible la tiranía de las grandes empresas del software sobre el mercado que impide un avance racional de la informática. Tras trabajar en el MIT desarollando el editor Emacs no le agradó que su trabajo fuese utilizado por las marcas comerciales para crear versiones propetarias. Ante esa situacion decidio crear un proyecto con vista que el fuente de los programas fuese accesible por todo el mundo. Ese es el GNU. Su objetivo era crear todo un sistema operativo de software abierto . El trabajo comenzo por desarrollar una versión libre de Emacs , un compilador ( el GCC ) y además el conjunto habitual de herramientas típicas de los sistemas Unix. Estas son las que este artículo analiza.

grep

En el ejemplo anterior hemos visto básicamente cual es el objetivo de grep . Ahora se especifica con más detalle.

grep básicamente funciona de esta manera:

$ grep [-opciones] patrón ficheros

Las opciones más comunes son:

-n antepone a cada linea emparejada con su número de línea (útil para buscar algo en un fichero muy largo y saber donde esta especificamente)
-c imprime solo el número de coincidencia encontradas
-v solo se buscan las no coincidencias ( cuando lo que buscamos es lo que no coincide con el patrón )

El patrón es cualquier conjunto de caracteres que se busca. Hay que indicar es que si van acompañados de un espacio grep confundira el patrón con los ficheros a buscar, eso se soluciona con la ayuda de los caracteres ".Por ejemplo:

$ grep "Hola mundo" fichero

Si buscamos alguna cadena que contenga un comodín , apóstrofes , comillas , redirreciones o barras del tipo "\", se deberá anteponer una barra "\" para asi indicar de que buscamos esa caracter en si y no la substitución del comodín , o que iniciamos una cadena de varias palabras .

$ grep \*\"\'\?\< fichero
Esto es una cadena chunga -> *"'?<

Expresiones regulares

grep y otros herramientas GNU son capaces de realizar busquedas más avanzadas. Eso se consigue con ayuda de las expresiones regulares. Las expresiones regulares cumplen una función parecida a los comodines en el shell, o sea hacen sustituciones de caracteres o conjunto de caracteres. Unos ejemplos:

$ grep c.n 

busca todas las ocurrencias que tenga una cadena con una c , cualquier letra y una t

$ grep [Bc]el

busca las ocurrencias Bel y cel.

$ grep [m-o]ata

Das las lineas que contengán mata, nata y oata.

$ grep [^m-o]ata

Da las lineas que contenga una cadena terminada en ata y que no contenga como primera letra m,m y o

$ grep "^Martin come"

Como salida las lineas que comienzen con Martin come , ojo vease que no esta entre corchetes , en este caso no es una negación de conjunto como en el anterior ejemplo sino como comienzo de línea.

$ grep "durmiendo$"

Encontrará las lineas terminadas en durmiendo. $ substituye a un fin de línea.

$ grep "^Caja San Fernando gana la liga$"

Busca aquellas lineas que sean exactamente eso.

Por supuesto estos caracteres para eliminar su significado de sustitución hay que anteponerles la obligatoria "\". Por ejemplo:

$ grep "E\.T\."

Buscara la secuencia E.T.

Find

Este comando se encarga de la busqueda de ficheros. En otro artículo de esta revista se ha explicado con bastante detalle. Así como la cosa no es redescrubir la rueda solo hago referencia a él.

cut y paste

En Unix la información solía guardarse en ficheros de texto ASCII organizados por campos verticales separados con un caracter diferenciador , este solia ser un tabulador o el carácter ":". Una de las necesidades que se suele producir en estos casos es separar los campos de un fichero y unirlos en otro. cut y paste realizan ese trabajo.

Vamos a usar como ejemplo el fichero /etc/passwd encargado de gestionar los usuarios. Su contenido se compone de 7 campos separados por ":" . Los campos son respectivamente y en este orden login,clave encriptada , identificación de usuario , identificación de grupo , geco , directorio de inicio de usuario y shell que usa.

He aquí un extracto típico de ese archivo.

root:x:0:0:root:/root:/bin/bash
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:x:501:501:Usuario de practicas para Ksh:/home/practica:/bin/ksh
wizardi:x:502:502:Wizard para nethack:/home/wizard:/bin/bash

Si por ejemplo ahora queremos ahora emparejar los usuarios con los login que usa debemos cortar los campos 1 y 7. Manos a la obra:

$ cut -f1,7 -d: /etc/passwd
root:/bin/bash
murie:/bin/bash
practica:/bin/ksh
wizard:/bin/bash

-f expecifica los campos a visualizar -d indica el separador a usar ( por defecto el tabulador ) y por último se encuentra el fichero a listar.

También es posible especificar intervalos de campos:

$ cut -f5-7 -d: /etc/passwd
root:/root:/bin/bash
Manuel Muriel Cordero:/home/murie:/bin/bash
Usuario de practicas para Ksh:/home/practica:/bin/ksh
Wizard para nethack:/home/wizard:/bin/bash

Dejo al lector como ejercicio averiguar el porqué de esa salida.

Ahora supongamos que hemos redirigido la salida con la ayuda de ">" a 2 ficheros y queremos unir las 2 salidas. Para ello esta paste.

$ paste salida1 salida2
root:/bin/bash:root:/root:/bin/bash
murie:/bin/bash:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:/bin/ksh:Usuario de practicas para Ksk:/home/practica:/bin/ksh
wizard:/bin/bash:Wizard para nethack:/home/wizard:/bin/bash

sort

Por ejemplo supongamos ahora que deseamos de un /etc/passwd ordenada según el geco. Para ello recurrimos a sort, la herramienta de ordenación.

$ sort -t: +4 /etc/passwd
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
practica:x:501:501:Usuario de practicas para Ksh:/home/practica:/bin/ksh
wizard:x:502:502:Wizard para nethack:/home/wizard:/bin/bash
root:x:0:0:root:/root:/bin/bash

Se puede apreciar que ha ordenado la salida , pero siguiendo el criterio de la tabla ASCII , si deseamos que no diferencia entre mayúsculas y minúsculas se haría con:

$ sort -t: +4f  /etc/passwd
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
root:x:0:0:root:/root:/bin/bash
practica:x:501:501:Usuario de practicas para Ksh:/home/practica:/bin/ksh
wizard:x:502:502:Wizard para nethack:/home/wizard:/bin/bash

-t es la opción que indica que separador se usa . +4 se refiere a cuantos campos hay que saltar antes de iniciar la ordenación. f indica que se ignore las diferencias entre mayúsculas y minúsculas

Se puede realizar una ordenación mucho más refinada. Por ejemplo ordenado primero de forma inversa según el shell que use y luego por el geco:

$ sort -t: +6r +4f /etc/passwd
practica:x:501:501:Usuario de practicas para Ksh:/home/practica:/bin/ksh
murie:x:500:500:Manuel Muriel Cordero:/home/murie:/bin/bash
root:x:0:0:root:/root:/bin/bash
wizard:x:502:502:Wizard para nethack:/home/wizard:/bin/bash

Ahora supóngase que disponemos un fichero en el que se archiva las personas y las deudas en cuestión de préstamos que tiene con usted. Un ejemplo "manga":

Son Goku:23450
Son Gohan:4570
Picolo:356700
Ranma 1/2:700

Si usted desea saber a cual primero le tiene que mandar el matón :-) deseará obtener una salida ordenada según morosos.

Si se realiza esta prueba se puede observar que:

$ sort +1 deudas
Ranma 1/2:700
Son Gohan:4570
Son Goku:23450
Picolo:356700

Esto no es precisamente lo que se espera debido a que se ha realizado una busqueda alfabética con un número diferente de digitos. La solución reside en la opcion n:

$ sort +1n deudas
Picolo:356700
Son Goku:23450
Son Gohan:4570
Ranma 1/2:700

Las opciones basicas de sort son estas

+n.m se salta los n primeros campos y los m siguientes caracteres antes de empezar la ordenación.
-n.m para la ordenación al llegar al n-esimo campo y m caracteres despues

y como modificadores de los parametros son:

-b ignora espacios en blanco iniciales
-d orden de diccionario ( solo se tienen en cuenta letras , numeros y espacios)
-f ignora la distinción entre mayúsculas y minúsculas.
-n orden aritmético
-r orden inverso

wc

wc como se ha visto ya es un contador de letras,lineas y palabras. Por defecto al introducir como parametro un fichero da como salida el número de lineas, palabras y caracteres que lo componen

Con las opciones podemos variar esa salida

-l solo da las lineas
-w solo da las palabras
-c solo da los caracteres

Herramientas de diferenciación: cmp,comm,diff

A veces es necesario saber en que se diferencián 2 versiones de un fichero. Este se usa especialmente en programación cuando hay varias personas trabajando en un mismo proyecto modificando los fuentes de los programas. Si se precisa saber las variaciones de una versión de otra se recurre a estas herramientas.

cmp es la más básica de todas. Compara dos ficheros e indica , si la hay , el lugar donde se produce la primera diferencia (número de caracter y línea de la diferencia)

$ cmp antigua nueva
antigua nueva differ: char 11234, line 333

comm es algo más avanzado. Su salida se produce en 3 columnas. La primera contiene las lineas únicas del primer fichero, la segunda las únicas del segunda y la tercera las comunes. Dispone de parametros númericos que establecen si deseas eliminar alguna de esas columnas. Son la -1 , -2 y -3 que indican a comm que no visualizen la primera, segunda y tercera columna. Con este ejemplo se observa las lineas que sólo están en el primer fichero y las comunes.

$ comm -2 antigua nueva

Por último está diff. Es una herramienta fundamental en programación de proyectos avanzados. Si alguna vez ha bajado un kernel para compilarlo sabra que puede bajarse los fuentes de la nueva o bajarse el patch con respecto a la anterior, que suele ser un fichero mas pequeño . Ese patch suele terminar en .diff lo que indica que es el resultado de una salida diff. Esta herramienta contiene una serie de comandos de editor ( vi , rcs ) de tal manera que se hagan idénticos los 2 ficheros. También es aplicable a directorios y todos los archivos que lo contienen. La utilidad es muy clara, al tener que bajar menor cantidad de fuente ( solo los cambios ) se aplica el parche ( con patch ) y se vuelve a compilar. Sin parametros la salida específica en estos formatos como se deben hacer los cambios de tal manera que el primero sea igual al segundo con comandos vi.

$ diff antigua nueva
3c3
< El Hobbit
---
> El Señor de los Anillos
78a79,87
> Tres anillos para los Reyes Elfos bajo el cielo.
> Siete pera los Señores Enanos en casas de piedra.
> Nueve para los Hombres Mortales condenados a morir.
> Uno para el Señor Oscuro, sobre el trono oscuro
> en la tierra de Mordor donde se extienden las Sombras.
> Un Anillo para gobernarlos a todos. Un Anillo para encontrarlos,
> un anillo para atraerlos a todos y atarlos a las tinieblas
> en la tierra de Mordor donde se extienden las Sombras.

3c3 expresa que se debe cambiar la línea 3 , quitando "El Hobbit" y substituyendolo por "El Señor de los Anillos". 78a79,87 indica que se debe insertar unas nuevas lineas 79 a la 87.

uniq

uniq es el encargado de eliminar las redundancias. Por ejemplo si deseamos obtener un listado de la gente conectada al ordenador en un momento dado deberemos hacer uso de who y de cut.

$ who | cut -f1 -d' '
root
murie
murie
practica

El resultado no es del todo perfecto. Falta eliminar la doble aparición de murie. Dicho y hecho.

$ who | cut -f1 -d' ' | uniq
root
murie
practica

Como nota indicar que el -d' ' indica que el separador es el espacio en blanco ya que who no separa usando tabuladores.

sed

sed es una de las herramientas más peculiares de Unix. sed significa Stream Editor ( o sea editor de flujo ) . Los editores suelen aceptar de forma interactiva las modificaciones que se desean insertar. Sed nos permite crear pequeños programas "shell scripts" parecidos a los batch de MS-DOS . Sed nos dan la capacidad de modificar de forma automática el contenido de un fichero , permitiendonos crear shell scripts que lo modifiquen "on the fly". Las capacidades de este editor son muy completas y por la extensión que tomaría el artículo no se verán aquí, por lo cual se adoptara una breve introducción dejando al usuario interesado recurrir a la documentación en formato de man e info que contiene linux sobre todos sus comandos.

Sed suele llamarse de esta forma:

$ sed 'comando-sed' fichero

Por ejemplo tengamos un fichero en el que deseamos reemplazar todos las apariciones de "Manolo" por "Fernando" . Manos a la obra:

$ sed 's/Manolo/Fernando/g' archivo

Y devuelve por salida estandar las modificaciones. Si se desea conservar el resultado se redigirá con ">"

Los usuarios de vi reconecerán inmediatamente que se trata de un comando típico de vi de busqueda y sustitución. En realidad los comandos de tipo ":" ( los que invocan a ex ) se pueden usar con sed.

La estructura de los ordenes sed consiste en indicar primero una cadena ( o secuencia de cadenas ) sobre las que actuar y luego el comando. Para indicar una cadena se puede indicar un numero, un intervalo de numeros o buscar un patron.

Los comandos usuales de sed
Comando	Acción
-------  ------
a\	añade las lineas siguientes a las lineas afectadas
c\	cambia las lineas afectadas por las lineas siguientes
d	borra las lineas afectadas
g	hace sustituciones generales, de todos los patrones
	localizados inserta en lugar de limitarse al primero
i\	inserta las lineas siguientes a las afectadas
p	imprime la línea, incluso con la opción -n
q	abandonada (quit) cuando se alcanza la línea especificada
r fichero 	lee un fichero , añadiendo el contenido a la salida
s/uno/dos	sustituye la cadena "uno" por "dos"
w fichero	copia esa linea a otro fichero
=	imprime el número de línea
! comando	aplica un comando a dicha línea

Con sed se puede especificar sobre que lineas o conjunto de lineas se aplica el comando:

$ sed '3d' archivo

Borrará la tercera línea del archivo

$ sed '2,4s/e/#/' fichero

Substituye el caracter e por # en las lineas del 2 a la 4 inclusive.

También es posible realizar comandos sobre lineas que contengan una determinada cadena haciendo uso , si se desea , de expresiones regulares explicadas con anterioridad.

$ sed '/[Qq]ueen/d' canciones

Borra todas las lineas que contengan la cadena "Queen" o "queen".

Con la ayuda de expresiones regulares podemos por ejemplo eliminar las lineas vacias de un fichero.

$ sed '/^$/d' archivo

Aunque esto no borrará las cadenas que contengan espacios. Con esta versión además se consigue ese propósito.

$ sed '/^ *$/d' archivo

La secuencia ' *' indica que se debe buscar cualquier combinación de cero o mas apariciones del patrón ' '.

$ sed '/InitMenu/a\
> gvim	gvim.xpm	exec gvim &'  .xvwmrc

Este ejemplo buscaria una linea que contenga la cadena InitMenu y despues
de esa le añadiria esa cadena. 

awk

Por último y no menos importante esta el comando awk. Para los que se extrañen por ese peculiar nombre , este proviene de sus creadores originales Alfred Aho, Brian Kernighan y Peter Weinberger.

La utilidad awk es una de las más interesantes de los sistemas Unix. Es un herramienta bastante compleja y avanzada que permite desde la linea de comandos realizar un variado conjunto de operaciones.

Cabe indicar de que awk y sed forman pieza clave de los shell scripts más complejos. Puede resultar realmente impresionante lo que se puede llegar a hacer sin hacer uso para nada de C o cualquier otro lenguaje compilado. Cabe destacar que por ejemplo el setup de la distribucion de slakware así como muchos CGI del web son en realidad shell scripts.

Últimamente el uso de las herramientas de la línea de comandos ha sido algo denostado, achacandole demasiada antiguedad para los entornos de ventanas que se usan actualmente así como la llegada de lenguaje Perl que pretende ser un substituto de shell scripting dan a indicar que estas herramientas están condenadas al olvido. En mi experiencia he podido comprobar que muchas aplicaciones ( incluso un pequeño gestor de base de datos ) es cuestión de pocas líneas de código en shell script.

Es aquí donde awk junto con sed pueden realizar una gran labor sobre información almacenada en formato ASCII. Con ellos podemos realizar labores iguales a la suma de un pequeño gestor de base de datos más una hoja de cálculo.

Supongamos una factura en la que se indica en un fichero los artículos comprados y su precio de venta al público. Por ejemplo este archivo "compras":

naranjas	5	250		
peras	3	120
manzanas	2	360

Se trata de un fichero con 3 campos separados por tabuladores. Ahora se desea crear un cuarto campo con el precio total por cada producto.

$ awk '{total=$2*$3; print $0 , total }' compras
naranjas	6	250	1250
peras	3	120	360
manzanas	2	360	720

total es una variable al que se le asignan los valores multiplicados de los campos segundo y tercero, luego a cada linea se imprime la linea completa ($0) y el total por linea.

awk es casi un entorno de programación por si solo , ideal para el tratamiento automatizado de información en ficheros de texto. Si el usuario ha descubierto con interes esta herramienta le animo a seguir descubriendo sus peculiaridades en las paginas man e info de su sistema.

Los shell scripts

Ya se ha referido a ellos anteriormente. Los shell scripts son secuencias de instrucciones ( comandos del sistema ) que se deben realizar.

Los shell scripts tienen como hermanos a los archivos batch de DOS. Con ellos el usuario esta habilitado para crear sus propios comandos a partir de combinaciones de otros.

Los shell scripts son capaces , por supuesto , de aceptar parametros, estos se almacenan en las variables $0 ( nombre del comandos ) $1 , $2 , ... , $9. Para referirse a los $1 al $9 se puede hacer uso de $*

Los shell scripts se pueden crear con cualquier editor. Para ejecutarlos se puede hacer con:

$ sh shell-script

o mejor darle permisos de ejecución al archivo con

$ chmod 700 shell-script

Y luego se puede ejecutar con sólo

$ shell-script

Por ahora se deja a los shell scripts y así terminamos este artículo. Ya en proximos números se retomará el tema. En el proximo artículo se hablará acerca de los editores más comunes en los Unix. El vi y el emacs. EL conocimiento de su uso es fundamental para cualquier usuario de Linux.

Recursos

Este artículo es introductorio y si el autor lo cree conveniente puede estudiar con más detalles en otros articulos de LinuxFocus como: Find Expresiones regulares Awk

Reseña de Blibiografia:

El señor de los anillos . Autor J.R.R Tolkien . Edicciones Minotauro (c) 1997