cómo extraer una cadena utilizando expresiones regulares

Soy nuevo en shell scripts. Quiero enviar una petición http usando curl y luego extraer alguna cadena usando expresiones regulares. Por ejemplo, ¿cómo puedo extraer un nombre de dominio de una respuesta http? (El ejemplo es sólo para fines de aprendizaje)

#!/bin/bash
name=$(curl google.com | grep "www\..*com")
echo "domain name is"
echo $name
Solución

Usando expresiones regulares bash:

re="http://([^/]+)/"
if [[ $name =~ $re ]]; then echo ${BASH_REMATCH[1]}; fi

Editar - OP pidió una explicación de la sintaxis. La sintaxis de expresiones regulares es un tema extenso que no puedo explicar en su totalidad aquí, pero intentaré explicar lo suficiente para entender el ejemplo.

re="http://([^/]+)/"

Esta es la expresión regular almacenada en una variable bash, re - es decir, lo que quieres que coincida con tu cadena de entrada, y con suerte extraer una subcadena. Desglosándolo:

  • http:// es sólo una cadena - la cadena de entrada debe contener esta subcadena para que la expresión regular coincida
  • [] Normalmente se utilizan corchetes para decir "coincide con cualquier carácter dentro de los corchetes". Así, c[ao]t coincidiría tanto con "cat" como con "cot". El carácter ^ dentro de [] modifica esto para decir "coincide con cualquier carácter excepto los que están dentro de los corchetes. Así que en este caso [^/] coincidirá con cualquier carácter excepto "/".
  • La expresión entre corchetes sólo coincidirá con un carácter. Si se añade un signo + al final de la misma, se dice "coincide con 1 o más de las sub-expresiones precedentes". Así que [^/]+ coincide con 1 o más del conjunto de todos los caracteres, excluyendo "/".
  • Poner () entre paréntesis alrededor de una subexpresión indica que quiere guardar lo que coincida con esa subexpresión para procesarlo más tarde. Si el lenguaje que está utilizando soporta esto, proporcionará algún mecanismo para recuperar estas subcomparaciones. Para bash, es la matriz BASH_REMATCH.
  • Por último, hacemos una coincidencia exacta en "/" para asegurarnos de que coincidimos hasta el final del nombre de dominio completo y el siguiente "/";

A continuación, tenemos que probar la cadena de entrada contra la expresión regular para ver si coincide. Podemos usar una condicional bash para hacerlo:

if [[ $name =~ $re ]]; then
    echo ${BASH_REMATCH[1]}
fi

En bash, los [[ ]] especifican una prueba condicional extendida, y pueden contener el operador de expresión regular bash =~. En este caso comprobamos si la cadena de entrada $nombre coincide con la expresión regular $re. Si coincide, entonces debido a la construcción de la expresión regular, tenemos garantizado que tendremos una subcomparación (por los paréntesis ()), y podemos acceder a ella usando el array BASH_REMATCH:

  • El elemento 0 de esta matriz ${BASH_REMATCH[0]} será la cadena completa coincidente con la expresión regular, es decir, "http://www.google.com/".
  • Los elementos subsiguientes de esta matriz serán los resultados subsiguientes de las subcomparaciones. Los elementos BASH_REMATCH se corresponderán con ellos en orden. Así que en este caso ${BASH_REMATCH[1]} contendrá "www.google.com", que creo que es la cadena que desea.

Tenga en cuenta que el contenido de la matriz BASH_REMATCH sólo se aplica a la última vez que se utilizó el operador de expresión regular =~. Por lo tanto, si va a realizar más coincidencias de expresiones regulares, debe guardar los contenidos que necesite de esta matriz cada vez.

Esto puede parecer una larga descripción, pero realmente he pasado por alto varias de las complejidades de las expresiones regulares. Pueden ser bastante potentes, y creo que con un rendimiento decente, pero la sintaxis de las expresiones regulares es compleja. Además, las implementaciones de expresiones regulares varían, por lo que diferentes lenguajes soportarán diferentes características y pueden tener sutiles diferencias en la sintaxis. En particular, el escape de caracteres dentro de una expresión regular puede ser un tema espinoso, especialmente cuando esos caracteres tendrían un significado diferente en el lenguaje en cuestión.


Tenga en cuenta que en lugar de establecer la variable $re en una línea separada y hacer referencia a esta variable en la condición, puede poner la expresión regular directamente en la condición. Sin embargo en bash 3.2, las reglas fueron cambiadas con respecto a si las comillas alrededor de tales expresiones regulares literales son requeridas o no. Poner la expresión regular en una variable separada es una forma directa de evitar esto, de modo que la condición funciona como se espera en todas las versiones de bash que soportan el operador de coincidencia =~.

Comentarios (1)

Una forma sería con sed. Por ejemplo:

echo $name | sed -e 's?http://www\.??'

Normalmente las expresiones regulares sed están delimitadas por `/', pero puedes usar '?' ya que estás buscando '/'. Aquí'hay otro truco de bash. La respuesta de @DigitalTrauma'me recordó que debía sugerirlo. Es parecido:

echo ${name#http://www.}

(DigitalTrauma también tiene crédito por recordarme que el "http://" debe ser manejado).

Comentarios (0)