Comment extraire / analyser une URL complète à partir d'une chaîne semi-aléatoire?

12

J'aimerais avoir bash parse / extract une URL complète (et seulement l'url) à partir d'une courte chaîne aléatoire.

Exemples:

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

ou

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

ou

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

ou

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

J'ai essayé d'utiliser cat foo_output | egrep -o "https?://[\w'-\.]*\s"mais cela ne semblait pas fonctionner.

Mike B
la source
Cela semble effrayant, selon ce que vous voulez faire avec l'URL extraite ...
vonbrand

Réponses:

24

As-tu essayé:

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

au lieu?

Notez que tout ce qui a une classe de caractère est considéré comme littéral, donc dire [\w]ne correspond pas à un mot . De plus, vous n'avez pas besoin d'échapper à un métacaractère regex dans une classe de personnage, c'est-à-dire que dire [\.]n'est pas tout à fait la même chose que [.].

devnull
la source
2
[^ ]est trop large, vous aurez envie d'exclure d' autres blancs, (, ), peut - être comas, et tous les caractères qui ne sont pas autorisés dans les URL.
Stéphane Chazelas
@StephaneChazelas Vous avez raison. Cependant, j'ai supposé que l'URL est précédée et suivie d'un espace, sauf au début ou à la fin de la ligne.
devnull
5

Les URI ne sont pas bien adaptés à la correspondance des expressions régulières lorsqu'ils sont intégrés dans le langage naturel. Cependant, l'état actuel de la technique est le modèle Regex amélioré et libéral amélioré de John Gruber pour la correspondance des URL . Telle qu'elle est actuellement publiée, la version à une ligne est la suivante:

(?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 semble également garder un sens ici , bien que son article de blog explique beaucoup mieux son corpus de test et les limites du modèle d'expression régulière.

Si vous souhaitez implémenter l'expression à partir de la ligne de commande, vous pouvez vous retrouver limité par le moteur d'expressions régulières que vous utilisez ou par des problèmes de citation du shell. J'ai trouvé un script Ruby comme la meilleure option, mais votre kilométrage peut varier.

CodeGnome
la source
2
Veuillez inclure l'expression régulière dans votre réponse au lieu de la lier.
terdon
@terdon, l'expression rationnelle complète est d'environ 60 lignes.
vonbrand
2
@vonbrand Je sais, je l'ai vu. Nous avons juste tendance à éviter de créer des liens avec des ressources externes. L'intérêt des sites SE est d'être un wiki. Que se passe-t-il si le blog auquel vous vous connectez devient hors ligne? Votre réponse deviendra inutile. Quoi qu'il en soit, 60 lignes, ce n'est pas beaucoup et ce n'est que 60 lignes pour la lisibilité.
terdon
2

Le problème avec les URL correspondantes est que presque tout peut être dans une URL:

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

Comme vous pouvez le voir, l'URL (valide) ci - dessus contient $, ?, #, &, ,, .et :. Fondamentalement, la seule chose que vous pouvez être sûr qu'une URL ne contient pas est un espace vide. Dans cet esprit, vous pouvez extraire vos URL avec un modèle aussi simple que:

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

Le \Scorrespond à tous les caractères non-espace dans les expressions régulières compatibles perl (PCRE), le -Pactive les PCRE grepet le -ofait imprimer uniquement le segment correspondant de la ligne.

terdon
la source
0

J'irais pour le chaînage mais un peu différent. Si vous avez un extrait de texte comme le vôtre dans un fichier texte appelé strings.txt, vous pouvez procéder comme suit:

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

Explication:

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 

Comme il est possible que l'URL ne fonctionne pas, vous pouvez effectuer une vérification d'erreur supplémentaire avec votre URL d'intérêt. par exemple wget -p URL -O /dev/null- il imprimera des codes d'erreur assez différents au cas où l'URL ne serait pas disponible, vous pouvez donc configurer une boucle pour traiter votre liste de liens et afficher leur état de validité.

Si vous extrayez finalement des liens à partir de fichiers html, il peut y avoir des problèmes seddans des cas spéciaux. Comme cela a été suggéré dans un (post) amusant que vous avez probablement déjà vu - il est préférable de ne pas utiliser d'expressions régulières mais un moteur d'analyse HTML. Un tel analyseur facilement disponible est le navigateur texte uniquement lynx(disponible sur n'importe quel linux). Cela vous permet de vider instantanément la liste de tous les liens dans un fichier, puis d'extraire les URL que vous souhaitez avec grep.

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

Cependant, cela ne fonctionnera pas sur la plupart des fichiers html ou des extraits de texte avec des liens.

r0berts
la source
-1

Juste egrep -o 'https?://[^ ")]+'

qui comprendra url()et "http"

Roberto Bertó
la source
3
En quoi est-ce différent de la réponse de devnull? J'espère que vous vous rendez compte que l'utilisation de egrepest déconseillée.
Anthon
Si vous avez une amélioration par rapport à une réponse existante, vous pouvez vous y référer via le lien "partager" sous cette réponse. Voir aussi les pages d'aide
Jeff Schaller
-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

ajoutez également la commande SED pour la stocker dans le fichier CSV:

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