viernes, 29 de julio de 2016

Reordenando

Los tres programas siguientes que vamos a ver se usan para extraer columnas de nuestro archivo de texto y recombinarlas de forma útil.

jueves, 28 de julio de 2016

uniq

Comparándolo con sort, el programa uniq es un peso pluma. uniq realiza una tarea que puede parecer trivial. Cuando, le damos un archivo ordenado (incluida la entrada estándar), elimina las líneas duplicadas y manda los resultados a la salida estándar. A menudo se usa junto con sort para limpiar la salida de duplicados.

Consejo: Mientras que uniq es una herramienta tradicional de Unix a menudo usada con sort, la versión GNU de sort soporta la opción -u, que elimina los duplicados de la salida ordenada.

Hagamos un archivo de texto para probarlo:

[me@linuxbox ~]$ cat > foo.txt
a
b
c
a
b
c

Recuerda pulsar Ctrl-d para finalizar la salida estándar. Ahora, si ejecutamos uniq en nuestro archivo de texto:

[me@linuxbox ~]$ uniq foo.txt
a
b
c
a
b
c

los resultados no son diferentes de nuestro archivo original; los duplicados no han sido eliminados. Para que uniq haga realmente su trabajo, la entrada debe ordenarse primero:

[me@linuxbox ~]$ sort foo.txt | uniq
a
b
c

Esto es porque uniq sólo elimina las líneas duplicadas que son contiguas entre sí.

uniq tiene varias opciones. Aquí están las más comunes:

Tabla 20-2: Opciones comunes de uniq
Opción Descripción
-c Muestra una lista de líneas duplicadas precedidas por el número de veces que aparece la línea.
-d Sólo muestra las líneas repetidas, en lugar de las líneas únicas.
-f n Ignora los primeros n campos en cada línea. Los campos se separan por espacios en blanco como en sort; sin embargo, al contrario que en sort, uniq no tiene una opción para configurar un separador de campos alternativo.
-i Ignora las mayúsculas durante la comparación de líneas.
-s n Se salta (ignora) los n primeros caracteres de cada línea.
-u Sólo muestra líneas únicas. Es la configuración por defecto.

Aquí vemos uniq usado para mostrar el número de duplicados encontrados en nuestro archivo de texto, usando la opción -c:

[me@linuxbox ~]$ sort foo.txt | uniq -c
      2 a
      2 b
      2 c

miércoles, 27 de julio de 2016

sort

El programa sort ordena el contenido de la entrada estándar, o de uno o más archivos especificados en la línea de comandos, y manda el resultado a la salida estándar. Usando la misma técnica que usamos con cat, podemos demostrar el procesado de la entrada estándar directamente desde el teclado:

[me@linuxbox ~]$ sort > foo.txt
c
b
a
[me@linuxbox ~]$ cat foo.txt
a
b
c

Tras introducir el comando, escribimos las letras "c", "b" y "a", seguidas de nuevo de Ctrl-d para indicar el final del archivo. Después vemos el archivo resultante y comprobamos que ahora las líneas aparecen ordenadas.

Como sort puede aceptar múltiples archivos en la línea de comandos como argumentos, es posible unir múltiples archivos en un único archivo ordenado. Por ejemplo, si tenemos tres archivos de texto y queremos combinarlos en un único archivo ordenado, podríamos hacer algo como esto:

sort file1.txt file2.txt file3.txt > final_sorted_list.txt

sort tiene varias opciones interesantes. Aquí hay una lista parcial:

Tabla 20-1: Opciones comunes de ordenamiento
Opción Opción larga Descripción
-b --ignore-leading-blanks Por defecto, el ordenado se realiza en la línea completa, empezando con el primer carácter de la línea. Esta opción hace que sort ignore los espacios al principio de la línea y calcula el ordenado basándose en el primer carácter que no es un espacio en blanco en la línea.
-f --ignore-case Hace que el ordenamiento no distinga entre mayúsculas y minúsculas.
-n --numeric-sort Realiza el ordenado basado en la evaluación numérica de una cadena. Usar esta opción permite que el ordenado se realice según valores numéricos en lugar de valores alfabéticos.
-r --reverse Ordena inversamente. Los resultados son descendentes en lugar de ascendentes.
-k --key=campo1[,campo2] Orden basado en un campo clave localizado entre campo1 y campo2 en lugar de en la línea entera. Veremos este tema luego.
-m --merge Trata cada argumento como el nombre de un archivo preordenado. Une múltiples archivos en uno sólo ordenado resultante sin realizar ningún ordenamiento adicional.
-o --output=archivo Envía salida ordenada a archivo en lugar de a la salida estándar.
-t --field-separator=carácter Define el caracter separador de campos. Por defecto los campos se separan por espacios o tabuladores.

Aunque la mayoría de las opciones anteriores son bastante autoexplicativas, algunas no lo son tanto. Primero veamos la opción -n, usada para ordenamiento numérico. Con esta opción, es posible ordenar valores basándonos en valores numéricos. Podemos demostrarlo ordenando los resultados del comando du para determinar los usuarios con más espacio en disco. Normalmente, el comando du lista los resultados de un sumario por orden de la ruta:

[me@linuxbox ~]$ du -s /usr/share/* | head
252    /usr/share/aclocal
96     /usr/share/acpi-support
8      /usr/share/adduser
196    /usr/share/alacarte
344    /usr/share/alsa
8      /usr/share/alsa-base
12488        /usr/share/anthy
8      /usr/share/apmd
21440        /usr/share/app-install
48     /usr/share/application-registry

En este ejemplo, canalizamos el resultado en head para limitar los resultados a las primeras diez líneas. Podemos producir una lista ordenada numéricamente para mostrar los diez mayores consumidores de espacio de esta forma:

[me@linuxbox ~]$ du -s /usr/share/* | sort -nr | head
509940 /usr/share/locale-langpack
242660 /usr/share/doc
197560 /usr/share/fonts
179144 /usr/share/gnome
146764 /usr/share/myspell
144304 /usr/share/gimp
135880 /usr/share/dict
76508        /usr/share/icons
68072        /usr/share/apps
62844        /usr/share/foomatic

Usando las opciones -nr, producimos un orden numérico inverso, con los mayores valores apareciendo primero en los resultados. Este orden funciona porque los valores numéricos están al principio de cada línea. Pero, ¿qué pasa si queremos ordenar una lista basándonos en algún valor localizado dentro de la línea? Por ejemplo, los resultados de un ls -l:

[me@linuxbox ~]$ ls -l /usr/bin | head
total 152948
-rwxr-xr-x 1 root root  34824 2008-04-04 02:42 [
-rwxr-xr-x 1 root root 101556 2007-11-27 06:08 a2p
-rwxr-xr-x 1 root root  13036 2008-02-27 08:22 aconnect
-rwxr-xr-x 1 root root  10552 2007-08-15 10:34 acpi
-rwxr-xr-x 1 root root   3800 2008-04-14 03:51 acpi_fakekey
-rwxr-xr-x 1 root root   7536 2008-04-19 00:19 acpi_listen
-rwxr-xr-x 1 root root   3576 2008-04-29 07:57 addpart
-rwxr-xr-x 1 root root  20808 2008-01-03 18:02 addr2line
-rwxr-xr-x 1 root root 489704 2008-10-09 17:02 adept_batch

Ignorando, por el momento, que ls puede ordenar sus resultados por tamaño, podríamos usar sort para ordenar la lista por tamaño de archivo, así:

[me@linuxbox ~]$ ls -l /usr/bin | sort -nr -k 5 | head
-rwxr-xr-x 1 root root 8234216 2008-04-07 17:42 inkscape
-rwxr-xr-x 1 root root 8222692 2008-04-07 17:42 inkview
-rwxr-xr-x 1 root root 3746508 2008-03-07 23:45 gimp-2.4
-rwxr-xr-x 1 root root 3654020 2008-08-26 16:16 quanta
-rwxr-xr-x 1 root root 2928760 2008-09-10 14:31 gdbtui
-rwxr-xr-x 1 root root 2928756 2008-09-10 14:31 gdb
-rwxr-xr-x 1 root root 2602236 2008-10-10 12:56 net
-rwxr-xr-x 1 root root 2304684 2008-10-10 12:56 rpcclient
-rwxr-xr-x 1 root root 2241832 2008-04-04 05:56 aptitude
-rwxr-xr-x 1 root root 2202476 2008-10-10 12:56 smbcacls

Muchos usos de sort implican el procesado de datos tabulares, como los resultados del comando ls anterior. Si aplicamos terminología de bases de datos a la tabla anterior, diríamos que cada fila es un registro consistente en múltiples campos, como los atributos de archivo, contador de enlaces, nombre de archivo, tamaño de archivo y así sucesivamente. sort puede procesar campos individuales. En términos de bases de datos, podemos especificar uno o más campos clave para usar como claves de ordenamiento. En el ejemplo anterior, especificamos las opciones n y r para realizar un ordenamiento numérico inverso y especificamos -k 5 para hacer que sort use el quinto campo como la clave de ordenamiento.

La opción k es muy interesante y tiene muchas funciones, pero primero tenemos que hablar sobre cómo sort define los campos. Consideremos un archivo de texto muy simple consistente en una única línea que contenga el nombre del autor:

William Shotts

Por defecto, sort ve esta línea con dos campos. El primer campo contiene los caracteres:

"William"

y el segundo campo contiene los caracteres:

" Shotts"

lo que significa que los caracteres de espacio en blanco (espacios y tabuladores) se usan como delimitadores entre los campos y que los delimitadores se incluyen en el campo cuando se realiza el ordenado.

Mirando de nuevo una línea de la salida de nuestro ls, podemos ver que una línea contiene ocho campos y que el quinto campo es el tamaño del archivo:

-rwxr-xr-x 1 root root 8234216 2008-04-07 17:42 inkscape

Para nuestra próxima serie de experimentos, consideraremos el siguiente archivo que contiene la historia de tres distribuciones Linux populares desarrolladas entre 2006 y 2008. Cada línea del archivo tiene tres campos: el nombre de la distribución, el número de versión y la fecha de publicación en formato MM/DD/YYYY:

SUSE    10.2   12/07/2006
Fedora  10     11/25/2008
SUSE    11.0   06/19/2008
Ubuntu  8.04   04/24/2008
Fedora  8      11/08/2007
SUSE    10.3   10/04/2007
Ubuntu  6.10   10/26/2006
Fedora  7      05/31/2007
Ubuntu  7.10   10/18/2007
Ubuntu  7.04   04/19/2007
SUSE    10.1   05/11/2006
Fedora  6      10/24/2006
Fedora  9      05/13/2008
Ubuntu  6.06   06/01/2006
Ubuntu  8.10   10/30/2008
Fedora  5      03/20/2006

Usando un editor de texto (quizá vim), introduciremos estos datos y nombraremos al archivo resultante distros.txt.

A continuación, trataremos de ordenar el archivo y observaremos el resultado:

[me@linuxbox ~]$ sort distros.txt
Fedora  10    11/25/2008
Fedora  5     03/20/2006
Fedora  6     10/24/2006
Fedora  7     05/31/2007
Fedora  8     11/08/2007
Fedora  9     05/13/2008
SUSE    10.1  05/11/2006
SUSE    10.2  12/07/2006
SUSE    10.3  10/04/2007
SUSE    11.0  06/19/2008
Ubuntu  6.06  06/01/2006
Ubuntu  6.10  10/26/2006
Ubuntu  7.04  04/19/2007
Ubuntu  7.10  10/18/2007
Ubuntu  8.04  04/24/2008
Ubuntu  8.10  10/30/2008

Bien, casi ha funcionado. El problema aparece en el ordenamiento de los números de versión de Fedora. Como un "1" viene antes que un "5" en el juego de caracteres, la versión "10" aparece arriba mientras que la versión "9" aparece al final.

Para arreglar este problema vamos a tener que ordenar por múltiples claves. Queremos realizar un orden alfabético en el primer campo y luego un orden numérico en el segundo campo. sort permite múltiples instancias de la opción -k así que pueden especificarse múltiples claves de ordenamiento. De hecho, una clave puede incluir un rango de campos. Si no se especifica un rango (como ha sido el caso de nuestros ejemplos anteriores), sort usa una clave que comienza con el campo especificado y se extiende hasta el final de la línea. Aquí tenemos la sintaxis de nuestro ordenamiento multi-clave:

[me@linuxbox ~]$ sort --key=1,1 --key=2n distros.txt
Fedora   5    03/20/2006
Fedora   6    10/24/2006
Fedora   7    05/31/2007
Fedora   8    11/08/2007
Fedora   9    05/13/2008
Fedora   10   11/25/2008
SUSE     10.1 05/11/2006
SUSE     10.2 12/07/2006
SUSE     10.3 10/04/2007
SUSE     11.0 06/19/2008
Ubuntu   6.06 06/01/2006
Ubuntu   6.10 10/26/2006
Ubuntu   7.04 04/19/2007
Ubuntu   7.10 10/18/2007
Ubuntu   8.04 04/24/2008
Ubuntu   8.10 10/30/2008

Aunque hemos usado la forma larga de la opción para que se vea más claramente, -k 1, 1 -k 2n sería completamente equivalente. En la primera instancia de la opción de clave, especificamos un rango de campos a incluir en la primera clave. Como queremos limitar el orden al primer campo solamente, especificamos 1, 1 que significa "comienza en el campo uno y termina en el campo uno." En la segunda instancia, hemos especificado 2n, que significa que el campo 2 es la clave de ordenamiento y que el orden debería ser numérico. Puede incluirse una letra de opción al final de un especificador de clave para indicar el tipo de orden a realizar. Estas letras de opción son las mismas que las opciones globales del programa sort: b (ignora los espacios en blanco iniciales), n (orden numérico), r (orden inverso), y así sucesivamente.

El tercer campo de nuestra lista contiene una fecha con un formato inapropiado para ordenarlo. En los ordenadores, las fechas están normalmente formateadas como YYYY-MM-DD para hacer más fácil el ordenamiento cronológico, pero la nuestra está en formato Americano MM/DD/YYYY. ¿Cómo podemos ordenar esta lista por orden cronológico?

Afortunadamente, sort nos da una forma. La clave de opción permite especificar compensaciones (offsets) dentro de campos, por lo que podemos definir claves dentro de campos:

[me@linuxbox ~]$ sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt
Fedora  10    11/25/2008
Ubuntu  8.10  10/30/2008
SUSE    11.0  06/19/2008
Fedora  9     05/13/2008
Ubuntu  8.04  04/24/2008
Fedora  8     11/08/2007
Ubuntu  7.10  10/18/2007
SUSE    10.3  10/04/2007
Fedora  7     05/31/2007
Ubuntu  7.04  04/19/2007
SUSE    10.2  12/07/2006
Ubuntu  6.10  10/26/2006
Fedora  6     10/24/2006
Ubuntu  6.06  06/01/2006
SUSE    10.1  05/11/2006
Fedora  5     03/20/2006

Especificando -k 3.7 le decimos a sort que use una clave de ordenación que comience en el séptimo carácter del tercer campo, que corresponde al principio del año. De igual forma, especificamos -k 3.1 y -k 3.4 para aislar las zonas del día y el mes de la fecha. También añadimos las opciones n y r para realizar un ordenado numérico inverso. La opción b se incluye para suprimir los espacios iniciales (cuyo número varía según la línea, afectando de este modo al resultado del ordenado) en el campo fecha.

Algunos archivos no usan tabuladores ni espacios como delimitadores de campos; por ejemplo, el archivo /etc/passwd:

[me@linuxbox ~]$ head /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh

Los campos en este archivo están delimitados por dos puntos (:), así que ¿cómo ordenamos este archivo usando un campo clave? sort cuenta con la opción -t para definir el carácter separador de campos. Para ordenar el archivo passwd por el séptimo campo (el shell por defecto de la cuenta), podríamos hacer esto:

[me@linuxbox ~]$ sort -t ':' -k 7 /etc/passwd | head
me:x:1001:1001:Myself,,,:/home/me:/bin/bash
root:x:0:0:root:/root:/bin/bash
dhcp:x:101:102::/nonexistent:/bin/false
gdm:x:106:114:Gnome Display Manager:/var/lib/gdm:/bin/false
hplip:x:104:7:HPLIP system user,,,:/var/run/hplip:/bin/false
klog:x:103:104::/home/klog:/bin/false
messagebus:x:108:119::/var/run/dbus:/bin/false
polkituser:x:110:122:PolicyKit,,,:/var/run/PolicyKit:/bin/false
pulse:x:107:116:PulseAudio daemon,,,:/var/run/pulse:/bin/false

Especificando el carácter de los dos puntos como separador de campos, podemos ordenar por el séptimo campo.

martes, 26 de julio de 2016

Texto MS-DOS Vs. Texto Unix

Una de las razones por las que querrías usar cat para buscar caracteres no imprimibles en el texto es para eliminar retornos de carro ocultos. ¿De dónde vienen los retornos de carro ocultos? ¡De DOS y Windows! Unix y DOS no definen el final de una línea de la misma forma en los archivos de texto. Unix finaliza una línea con un carácter salto de línea (ASCII 10) mientras que MS-DOS y sus derivados usan la secuencia del retorno de carro (ASCII 13) y salto de línea para terminar cada línea de texto.

Hay varias formas de convertir archivos de formato DOS a UNIX. En muchos sistemas Linux, hay programas llamados dos2unix y unix2dos, que pueden convertir archivos de texto de y hacia formato DOS. Sin embargo, si no tienes dos2unix en tu sistema, no te preocupes. El proceso de convertir texto de formato DOS a Unix es muy simple; simplemente implica eliminar los retornos de carro innecesarios. Esto lo realizan fácilmente un par de programas que veremos más tarde en este capítulo.

lunes, 25 de julio de 2016

cat

El programa cat tiene un gran número de opciones interesantes. Muchas de ellas se usan para ayudarnos a visualizar mejor el contenido del texto. Un ejemplo es la opción -A, que se usa para mostrar caracteres no imprimibles en el texto. Hay veces que queremos saber si los caracteres de control están incrustados en nuestro texto visible. Los más comunes son los caracteres de tabulación (en lugar de espacios) y retornos de carro, a menudo presentes como caracteres de fin de línea en archivos de texto estilo MS-DOS. Otra situación común es un archivo que contiene líneas de texto con espacios al final.

Creemos un archivo de prueba usando cat como un procesador de texto primitivo. Para hacerlo, simplemente introduciremos el comando cat (sólo especificando un archivo para redirigir la salida) y escribiremos nuestro texto, seguido de Enter para terminar la línea apropiadamente, luego Ctrl-d para indicar a cat que hemos alcanzado el final del archivo. En este ejemplo, introducimos un carácter tabulador al principio y continuamos la línea con algunos espacios al final:

[me@linuxbox ~]$ cat > foo.txt
     The quick brown fox jumped over the lazy dog.
[me@linuxbox ~]$

A continuación, usaremos cat con la opción -A para mostrar el texto:

[me@linuxbox ~]$ cat -A foo.txt
^IThe quick brown fox jumped over the lazy dog.   $
[me@linuxbox ~]$

Como podemos ver en los resultados, el carácter tabulador en nuestro texto se representa como ^I. Es una notación común que significa "Control-I" que, resulta ser igual que un carácter de tabulación. También vemos que aparece un $ al final real de la línea, indicando que nuestro texto contiene espacios al final.

cat también tiene opciones que se usan para modificar texto. Las dos más destacadas son -n, que numera las líneas, y -s, que suprime la salida de líneas en blanco múltiples. Podemos demostrarlo así:

[me@linuxbox ~]$ cat > foo.txt
The quick brown fox


jumped over the lazy dog.
[me@linuxbox ~]$ cat -ns foo.txt
    1     The quick brown fox
    2
    3     jumped over the lazy dog.
[me@linuxbox ~]$

En este ejemplo, hemos creado una nueva versión de nuestro archivo de prueba foo.txt, que contiene dos líneas de texto separadas por dos líneas en blanco. Tras procesarlo con cat con las opciones -ns, la línea en blanco extra se elimina y el resto de líneas son numeradas. Aunque no es un proceso muy grande a realizar sobre el texto, es un proceso.

viernes, 22 de julio de 2016

Volviendo a visitar antiguos amigos

Volviendo al Capítulo 6 (Redirección), aprendimos algunos comandos que sirven para aceptar entrada estándar además de argumentos de línea de comandos. En ese momento sólo los vimos brevemente, pero ahora le echaremos un vistazo más de cerca para ver cómo pueden usarse para realizar procesado de texto.

jueves, 21 de julio de 2016

Código fuente de programas

Muchos de los programas de la línea de comandos que encontramos en los sistemas tipo Unix fueron creados para soportar administración de sistemas y desarrollo de software, y los programas de procesado de texto no son una excepción. Muchos de ellos están diseñados para resolver problemas de desarrollo de software. La razón por la que el procesado de texto es importante para los desarrolladores de software es que todo software nace como un texto. El código fuente, la parte del programa que el programador realmente escribe, siempre está en formato texto.

miércoles, 20 de julio de 2016

Salida de impresora

En sistemas tipo Unix, la salida destinada para una impresora se manda como texto plano o, si la página contiene gráficos, se convierte en un formato de texto en lenguaje de descripción de página llamado PostScript, que se envía a un programa que genera los puntos gráficos a imprimir.

martes, 19 de julio de 2016

Email

El email es un medio intrínsecamente basado en texto. Incluso los archivos adjuntos que no son texto son convertidos a una representación textual para transmitirlos. Podemos ver esto nosotros mismos descargando un mensaje de email y viéndolo con less. Veremos que el mensaje comienza con un encabezado que describe la fuente del mensaje y el procesado que ha recibido durante su viaje, seguido por un cuerpo del mensaje con su contenido.

lunes, 18 de julio de 2016

Páginas web

El tipo de documento electrónico más popular del mundo es probablemente la página web. Las páginas web son documentos de texto que usan HTML (Hypertext Markup Language - Lenguaje de marcas de hipertexto) o XML (Extensible Markup Language - Lenguaje de marcas extensible) como lenguajes de marcas para describir el formato visual de los documentos.

viernes, 15 de julio de 2016

Documentos

Mucha gente escribe documentos usando formatos de texto plano. Aunque es fácil ver cómo un archivo pequeño de texto puede ser útil para guardar notas simples, también es posible escribir grandes documentos en formato texto. Un enfoque popular es escribir un documento grande en formato texto y luego usar un lenguaje de marcas para describir el formato del documento final. Muchos trabajos científicos están escritos usando este método, ya que los sistemas de procesado de texto basados en Unix fueron casi los primeros sistemas que soportaron diseños de tipografía avanzada necesarios para los escritores de disciplinas técnicas.

jueves, 14 de julio de 2016

Aplicaciones de texto

Hasta ahora, hemos aprendido un par de editores de texto (nano y vim), hemos visto un puñado de archivos de configuración, y hemos presenciado la salida de docenas de comandos, todo en texto. Pero ¿para qué más se usa el texto? Resulta que para muchas cosas.

miércoles, 13 de julio de 2016

Procesado de texto

Todos los sistemas operativos tipo Unix dependen en gran medida de los archivos de texto para varios tipos de almacenamiento de datos. Así que tiene sentido que haya muchas herramientas para manipular texto. En este capítulo, veremos programas que se usan para "desmenuzar" texto. En el siguiente capítulo, veremos más procesado de texto, centrándonos en programas que se utilizan para formatear el texto para imprimirlo y otros tipos de consumo humano.

Este capítulo volverá a visitar a algunos viejos amigos y nos presentará algunos nuevos:
  • cat - Concatena archivos e imprime en la salida estándar
  • sort - Ordena líneas en archivos de texto
  • uniq - Reporta u omite líneas repetidas
  • cut - Elimina secciones de cada línea de archivos
  • paste - Une lineas de archivos
  • join - Une líneas de dos archivos en un campo común
  • comm - Compara dos archivos ordenados línea por línea
  • diff - Compara archivos línea por línea
  • patch - Aplica un archivo de diferencia a uno original
  • tr - Traduce o borra caracteres
  • sed - Editor de flujos para filtrar y transformar texto
  • aspell - Corrector ortográfico interactivo

martes, 12 de julio de 2016

Para saber más

Hay muchos recursos online para aprender expresiones regulares, incluyendo varios tutoriales y chuletas.

Además, la Wikipedia tiene buenos artículos en los siguientes enlaces:

lunes, 11 de julio de 2016

Resumiendo

En este capítulo, hemos visto algunos de los muchos usos de las expresiones regulares. Podemos encontrar incluso más si usamos expresiones regulares para buscar aplicaciones adicionales que las usen. Podemos hacerlo buscando en las man pages:

[me@linuxbox ~]$ cd /usr/share/man/man1
[me@linuxbox man1]$ zgrep -El 'regex|regular expression' *.gz

El programa zgrep proporciona una interfaz para grep, permitiéndonos leer archivos comprimidos. En nuestro ejemplo, buscamos la sección uno de la man page comprimida en su localización usual. El resultado de este comando es una lista de archivos que contienen la cadena "regex" o la cadena "regular expression". Como podemos ver, las expresiones regulares aparecen en un montón de programas.

Hay una función en las expresiones regulares básicas que no hemos visto. Se llaman retroreferencias (back references), esta característica será tratada en el siguiente capítulo.

viernes, 8 de julio de 2016

Buscando texto con less y vim

less y vim comparten el mismo método de búsqueda de texto. Pulsando la tecla / seguida de una expresión regular realizaremos una búsqueda. Si usamos less para ver nuestro archivo phonelist.txt:

[me@linuxbox ~]$ less phonelist.txt

y luego buscamos por nuestra expresión de validación:

(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
~
~
~
/^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$

less resaltará las cadenas que coinciden, dejando las que no valen fáciles de eliminar:

(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
~
~
~
(END)

vim, por otra parte, soporta expresiones regulares básicas, de forma que nuestra expresión aparecería así:

/([0-9]\{3\}) [0-9]\{3\}-[0-9]\{4\}

Podemos ver que la expresión es prácticamente igual; sin embargo, muchos de los caracteres que se consideran metacaracteres en expresiones extendidas se consideran literales en expresiones básicas. Sólo se tratan como metacaracteres cuando los escapamos con una barra invertida. Dependiendo de la configuración particular de vim en nuestro sistema, la coincidencia será resaltada. Si no, prueba este comando de modos:

:hlsearch

para activar la búsqueda resaltada.

Nota: Dependiendo de tu distribución, vim soportará o no la búsqueda resaltada. Ubuntu, en particular, proporciona una versión muy simplificada de vim por defecto. En ese tipo de sistemas, puedes usar tu administrador de paquetes para instalar la versión completa de vim.

jueves, 7 de julio de 2016

Buscando archivos con locate

El programa locate soporta expresiones regulares tanto básicas (la opción --regexp) como extendidas (la opción --regex). Con él, podemos realizar muchas de las mismas operaciones que hicimos antes con nuestros archivos dirlist:

[me@linuxbox ~]$ locate --regex 'bin/(bz|gz|zip)'
/bin/bzcat
/bin/bzcmp
/bin/bzdiff
/bin/bzegrep
/bin/bzexe
/bin/bzfgrep
/bin/bzgrep
/bin/bzip2
/bin/bzip2recover
/bin/bzless
/bin/bzmore
/bin/gzexe
/bin/gzip
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit

Usando alternancia, realizamos un búsqueda de rutas que contengan bin/bz, bin/gz o /bin/zip.

miércoles, 6 de julio de 2016

Encontrando nombres de archivos feos con find

El comando find soporta un test basado en un expresión regular. Hay una consideración importante a tener en cuenta cuando usamos expresiones regulares con find en lugar de grep. Mientras que grep imprimirá una linea cuando la línea contiene una cadena que coincide con una expresión, find requiere que la ruta coincida exactamente con la expresión regular. En el siguiente ejemplo, usaremos find con una expresión regular para encontrar cada ruta que contenga cualquier carácter que no sea miembro de la siguiente lista:

[-_./0-9a-zA-Z]

Un escaneo como este revelará rutas que contengan espacios y otros potenciales caracteres ofensivos:

[me@linuxbox ~]$ find . -regex '.*[^-_./0-9a-zA-Z].*'

Debido al requerimiento de que coincida exactamente la ruta completa, usamos .* en ambos extremos de la expresión para buscar cero o más instancias de cada carácter. En el centro de la expresión, usamos una expresión entre corchetes negada conteniendo nuestra colección de caracteres de ruta aceptables.

martes, 5 de julio de 2016

Validando una lista de teléfonos con grep

En nuestro ejemplo anterior, vimos como comprobábamos si un número telefónico estaba correctamente formateado. Un escenario más realista sería chequear una lista de números en su lugar, así que hagamos una lista. Haremos esto recitando un conjuro mágico a la línea de comandos. Será mágico porque no hemos visto la mayoría de los comandos involucrados, pero no te preocupes. Los veremos en próximos capítulos. Aquí está el conjuro:

[me@linuxbox ~]$ for i in {1..10}; do echo "(${RANDOM:0:3}) ${RANDOM:0:3}-${RANDOM:0:4}" >> phonelist.txt; done

Este comando producirá un archivo llamado phonelist.txt que contiene diez números de teléfono. Cada vez que repetimos el comando, otros diez números se añaden a la lista. También podemos cambiar el valor 10 que está cerca del principio del comando, para producir más o menos números de teléfono. Si examinamos el contenido del archivo, sin embargo, vemos que tenemos un problema:

[me@linuxbox ~]$ cat phonelist.txt
(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440

Algunos números están mal formateados, lo que es perfecto para nuestro propósito, ya que usaremos grep para validarlos.

Un método de validación útil sería escanear el archivo para encontrar números no válidos y mostrar la lista resultante en pantalla:

[me@linuxbox ~]$ grep -Ev '^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$'
phonelist.txt
(292) 108-518
(129) 44-1379
[me@linuxbox ~]$

Aquí usamos la opción -v para producir la coincidencia inversa ya que sólo mostraremos líneas de la lista que no coincidan con la expresión especificada. La propia expresión incluye metacaracteres ancla en los extremos para asegurarnos que el número no tiene caracteres extra al final. Esta expresión también requiere que estén presentes los paréntesis en un número válido, al contrario que nuestro número de teléfono del ejemplo anterior.

lunes, 4 de julio de 2016

Poniendo las expresiones regulares a trabajar

Veamos algunos comandos que ya sabemos para ver como pueden usarse con expresiones regulares.

viernes, 1 de julio de 2016

{} - Encuentra un elemento un número específico de veces

Los metacaracteres { y } se usan para expresar el número mínimo y máximo de coincidencias requeridas. Pueden especificarse de cuatro formas diferentes:

Tabla 19-3: Especificando el número de coincidencias
Especificador Significado
{n} Encuentra el elemento precedente si ocurre exactamente n veces.
{n,m} Encuentra el elemento precedente si ocurre al menos n veces, pero no más de m veces.
{n,} Encuentra el elemento precedente si ocurre n o más veces.
{,m} Encuentra el elemento precedente si ocurre no más de m veces.

Volviendo a nuestro ejemplo anterior con los números de teléfono, podemos usar este método de especificar repeticiones para simplificar nuestra expresión regular de:

^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$

a:

^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$

Probémoslo:

[me@linuxbox ~]$ echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
(555) 123-4567
[me@linuxbox ~]$ echo "555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
555 123-4567
[me@linuxbox ~]$ echo "5555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
[me@linuxbox ~]$

Como podemos ver, nuestra expresión revisada puede validar correctamente tanto los números con paréntesis como sin paréntesis, mientras que rechaza aquellos números que no están formateados correctamente.