Come posso estrarre / analizzare un URL completo da una stringa semi casuale?


12

Vorrei che bash analizzasse / estraesse un URL completo (e solo l'URL) da una stringa corta casuale.

Esempi:

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

Ho provato a usare cat foo_output | egrep -o "https?://[\w'-\.]*\s"ma non sembra funzionare.


Sembra spaventoso, a seconda di cosa vuoi fare con l'URL estratto ...
vonbrand

Risposte:


24

Hai provato:

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

anziché?

Nota che qualsiasi cosa con una classe di caratteri è considerata letterale, quindi dire [\w]non corrisponde a un carattere di parola . Inoltre, non è necessario sfuggire a un metacarattere regex all'interno di una classe di caratteri, ovvero dire che [\.]non è proprio lo stesso [.].


2
[^ ]è troppo largo, ti consigliamo di escludere altre spazi vuoti, (, ), possibilmente coma, e tutti i personaggi che non sono consentiti negli URL.
Stéphane Chazelas

@StephaneChazelas Hai ragione. Tuttavia, ho ipotizzato che l'URL sia preceduto e seguito da uno spazio a meno che all'inizio o alla fine della riga.
Devnull

5

Gli URI non sono adatti per la corrispondenza di espressioni regolari se incorporati in linguaggio naturale. Tuttavia, l'attuale stato dell'arte è il modello Regex migliorato, accurato, liberale e accurato di John Gruber per gli URL corrispondenti . Come attualmente pubblicato, la versione di una riga è la seguente:

(?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`!()\[\]{};:'".,<>?«»“”‘’]))

Anche John sembra mantenere un senso qui , sebbene il suo post sul blog faccia un lavoro molto migliore nel spiegare il suo corpus di test e i limiti del modello di espressione regolare.

Se desideri implementare l'espressione dalla riga di comando, potresti trovarti limitato dal motore di espressioni regolari che stai utilizzando o dai problemi di quotazione della shell. Ho trovato uno script di Ruby come l'opzione migliore, ma il tuo chilometraggio può variare.


2
Includi il regex nella tua risposta invece di collegarti ad esso.
terdon

@terdon, la regexp completa è di circa 60 righe.
vonbrand

2
@Vonbrand Lo so, l'ho visto. Tendiamo solo ad evitare il collegamento a risorse esterne. Il punto centrale dei siti SE è di essere un wiki. E se il blog a cui ti sei collegato non è in linea? La tua risposta diventerà inutile. In ogni caso, 60 righe non sono così tante ed è solo 60 righe per la leggibilità.
terdon

2

Il problema con la corrispondenza degli URL è che qualsiasi cosa può trovarsi in un URL:

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

Come si può vedere, la (valido) URL sopra contiene $, ?, #, &, ,, .e :. Fondamentalmente, l'unica cosa che puoi essere sicuro che un URL non contenga è uno spazio vuoto. Con questo in mente, puoi estrarre i tuoi URL con un modello semplice come:

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

L' \Scorrisponde a qualsiasi non spaziali personaggi di espressioni regolari Perl compatibili (PCREs), l' -Pattiva PCREs per grepe la -orende stampare solo il segmento abbinato della linea.


0

Vorrei concatenarmi, ma un po 'diverso. Se hai un frammento di testo come il tuo in un file di testo chiamato strings.txt, puoi fare come segue:

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

Spiegazione:

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 

Poiché esiste la possibilità che l'URL potrebbe non funzionare, è possibile eseguire ulteriori controlli degli errori con l'URL di interesse. ad esempio wget -p URL -O /dev/null: stamperà codici di errore abbastanza diversi nel caso in cui l'URL non sia disponibile, quindi è possibile impostare un ciclo per elaborare l'elenco dei collegamenti e generare il loro stato di validità.

Se in definitiva stai estraendo collegamenti da file html, in alcuni sedcasi particolari potrebbero esserci dei problemi . Come è stato suggerito in un divertente (post) che probabilmente hai già visto, potrebbe essere meglio non usare regexps ma un motore di analisi HTML. Uno di questi parser facilmente disponibili è il solo browser di testo lynx(disponibile su qualsiasi Linux). Ciò ti consente di scaricare istantaneamente l'elenco di tutti i collegamenti in un file e quindi estrarre gli URL che desideri con grep.

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

Tuttavia, ciò non funzionerà sulla maggior parte dei file html o snippet di testo con collegamenti.


-1

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

che includerà url()e "http"


3
In che modo differisce dalla risposta di devnull? Spero che tu ti renda conto che l'uso di egrepè deprecato.
Anthon,

Se hai un miglioramento rispetto a una risposta esistente, puoi fare riferimento nuovamente al link "condividi" sotto quella risposta. Vedi anche le pagine di aiuto
Jeff Schaller

-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

in alternativa aggiungi il comando SED per memorizzarlo nel file CSV:

| sed 's/;/<tab>/g' > file.csv
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.