¿Cómo puedo extraer / analizar una URL completa de una cadena semi aleatoria?

12

Me gustaría que bash analice / extraiga una URL completa (y solo la URL) de una cadena corta aleatoria.

Ejemplos:

bob, the address is http://www.google.com

o

https://foo.com/category/example.html is up

o

Error 123 occurred at http://bit.ly/~1223456677878

o

Stats are up: https://foo1234.net/report.jpg

Traté de usar cat foo_output | egrep -o "https?://[\w'-\.]*\s"pero eso no pareció funcionar.

Mike B
fuente
Suena aterrador, dependiendo de lo que quieras hacer con la URL extraída ...
vonbrand

Respuestas:

24

Has probado:

egrep -o 'https?://[^ ]+' foo_output

¿en lugar?

Tenga en cuenta que cualquier cosa con una clase de caracteres se toma como literal, por lo que decir [\w]no coincide con un carácter de palabra . Además, no necesita escapar de un metacarácter regex dentro de una clase de caracteres, es decir, decir [\.]que no es lo mismo que [.].

devnull
fuente
2
[^ ]es demasiado amplia, tendrá que excluir otros espacios en blanco, (, ),, posiblemente, comas, y todos los caracteres que no están permitidos en las direcciones URL.
Stéphane Chazelas
@StephaneChazelas Tienes razón. Sin embargo, supuse que la URL está precedida y seguida de un espacio a menos que sea al principio o al final de la línea.
devnull
5

Los URI no son adecuados para la coincidencia de expresiones regulares cuando se incrustan en lenguaje natural. Sin embargo, el estado actual de la técnica es el patrón de expresiones regulares precisas y liberales de John Gruber para las URL coincidentes . Como se publica actualmente, la versión de una línea es la siguiente:

(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

John también parece mantener una esencia aquí , aunque su entrada en el blog hace un trabajo mucho mejor al explicar su corpus de prueba y las limitaciones del patrón de expresión regular.

Si desea implementar la expresión desde la línea de comando, puede verse limitado por el motor de expresión regular que está utilizando o por problemas de comillas. He encontrado que un script de Ruby es la mejor opción, pero su kilometraje puede variar.

CodeGnome
fuente
2
Incluya la expresión regular en su respuesta en lugar de vincularla.
terdon
@terdon, la expresión regular completa es de unas 60 líneas.
vonbrand
2
@vonbrand Lo sé, lo vi. Solo tendemos a evitar vincularnos con recursos externos. El objetivo de los sitios de SE es ser un wiki. ¿Qué sucede si el blog al que se vinculó se desconecta? Tu respuesta se volverá inútil. De todos modos, 60 líneas no es tanto y solo son 60 líneas para facilitar la lectura.
terdon
2

El problema con las URL coincidentes es que casi cualquier cosa puede estar en una URL:

https://encrypted.google.com/search?hl=en&q=foo#hl=en&q=foo&tbs=qdr:w,sbd:1

Como se puede ver, el (válido) URL anterior contiene $, ?, #, &, ,, .y :. Básicamente, lo único de lo que puede estar seguro es que una URL no contiene es un espacio en blanco. Con eso en mente, puede extraer sus URL con un patrón tan simple como:

$ grep -oP 'http.?://\S+' file 
http://www.google.com
https://foo.com/category/example.html
http://bit.ly/~1223456677878
https://foo1234.net/report.jpg

El \Scoincide con cualquier no espaciales caracteres en Perl expresiones regulares compatibles (PCREs), la -Pactiva PCREs para grepy la -ohace imprimir sólo el segmento de emparejado de la línea.

terdon
fuente
0

Iría por encadenar pero un poco diferente. Si tiene un fragmento de texto como el suyo en un archivo de texto llamado strings.txt, puede hacer lo siguiente:

grep http ./strings.txt | sed 's/http/\nhttp/g' | grep ^http | sed 's/\(^http[^ <]*\)\(.*\)/\1/g' | grep IWANTthis | sort -u

Explicación:

grep http ./st3.txt      => will catch lines with http from text file
sed 's/http/\nhttp/g'    => will insert newline before each http
grep ^http               => will take only lines starting with http
sed 's/\(^http[^ <]*\)\(.*\)/\1/g'   
                         => will preserve string from ^http until first space or < (the latter in hope if 
grep IWANTthis           => will take only urls containing your text of your interest; you can omit this.
sort -u                  => will sort the list and remove duplicates from it 

Como existe la posibilidad de que la url no funcione, puede realizar una comprobación adicional de errores con su URL de interés. por ejemplo wget -p URL -O /dev/null, imprimirá códigos de error bastante diferentes en caso de que la URL no esté disponible, por lo que podría configurar un bucle para procesar su lista de enlaces y generar su estado de validez.

Si finalmente está extrayendo enlaces de archivos html, puede haber algunos problemas seden casos especiales. Como se ha sugerido en una divertida (publicación) que probablemente ya haya visto, puede ser mejor no usar expresiones regulares sino un motor de análisis html. Uno de estos analizadores fácilmente disponibles es el navegador de solo texto lynx(disponible en cualquier Linux). Esto le permite volcar instantáneamente la lista de todos los enlaces en un archivo y luego simplemente extraer las URL que desee con grep.

lynx -dump -listonly myhtmlfile.html | grep IWANTthisString | sort -u

Sin embargo, esto no funcionará en la mayoría de los archivos html maltratados o fragmentos de texto con enlaces.

r0berts
fuente
-1

Sólo egrep -o 'https?://[^ ")]+'

que incluirá url()y "http"

Roberto Bertó
fuente
3
¿Cómo es esto diferente de la respuesta de devnull? Espero que te des cuenta de que el uso de egrepestá en desuso.
Anthon
Si tiene una mejora con respecto a una respuesta existente, puede consultarla a través del enlace "compartir" debajo de esa respuesta. Consulte también las páginas de ayuda
Jeff Schaller
-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

como alternativa, agregue el comando SED para almacenarlo en el archivo CSV:

| sed 's/;/<tab>/g' > file.csv
MakoBuk
fuente