Como posso extrair / analisar um URL completo de uma sequência semi-aleatória?

12

Eu gostaria que o bash analisasse / extraísse um URL completo (e apenas o URL) de uma sequência curta aleatória.

Exemplos:

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

Eu tentei usar, cat foo_output | egrep -o "https?://[\w'-\.]*\s"mas isso não parecia funcionar.

Mike B
fonte
Parece assustador, dependendo do que você quer fazer com o URL extraído de ...
vonbrand

Respostas:

24

Você tentou:

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

em vez de?

Observe que qualquer coisa com uma classe de caractere é tomada como literal, portanto, dizer [\w]não corresponde a um caractere de palavra . Além disso, você não precisa escapar de um metacaractere regex dentro de uma classe de personagem, ou seja, dizer [\.]não é exatamente o mesmo que [.].

devnull
fonte
2
[^ ]é muito grande, você vai querer excluir outros espaços em branco, (, ),, possivelmente, comas, e todos os caracteres que não são permitidos em URLs.
Stéphane Chazelas
@StephaneChazelas Você está certo. No entanto, presumi que o URL fosse precedido e seguido por um espaço, a menos que no início ou no final da linha.
devnull
5

Os URIs não são adequados para correspondência de expressão regular quando incorporados em linguagem natural. No entanto, o estado da técnica atual é o Liberal Melhorado, Padrão Regex Preciso de John Gruber para URLs Correspondentes . Conforme publicado atualmente, a versão de uma linha é a seguinte:

(?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 também parece manter uma essência aqui , embora sua entrada no blog faça um trabalho muito melhor ao explicar seu corpus de teste e as limitações do padrão de expressão regular.

Se você deseja implementar a expressão na linha de comando, pode se sentir limitado pelo mecanismo de expressão regular que está usando ou por problemas de citação de shell. Eu achei o script Ruby a melhor opção, mas sua milhagem pode variar.

CodeGnome
fonte
2
Inclua a regex na sua resposta em vez de vincular a ela.
terdon
@terdon, o regexp completo é de cerca de 60 linhas.
vonbrand
2
@ vonbrand eu sei, eu vi. Nós apenas tendemos a evitar links para recursos externos. O objetivo dos sites da SE é ser um wiki. E se o blog ao qual você vinculou ficar offline? Sua resposta se tornará inútil. Enfim, 60 linhas não é muito e são apenas 60 linhas para facilitar a leitura.
terdon
2

O problema com os URLs correspondentes é que praticamente qualquer coisa pode estar em um URL:

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

Como você pode ver, o URL (válido) acima contém $, ?, #, &, ,, .e :. Basicamente, a única coisa que você pode ter certeza de que um URL não contém é um espaço em branco. Com isso em mente, você pode extrair seus URLs com um padrão tão simples quanto:

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

Ele \Scorresponde a qualquer caractere que não seja espaço em expressões regulares compatíveis com perl (PCREs), -Pativa PCREs grepe -ofaz com que ele imprima apenas o segmento correspondente da linha.

terdon
fonte
0

Eu iria encadear, mas um pouco diferente. Se você tiver um snippet de texto como o seu em um arquivo de texto chamado strings.txt, poderá fazer o seguinte:

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

Explicação:

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 a possibilidade de o URL não funcionar, você pode fazer uma verificação de erro adicional com seu URL de interesse. por exemplo wget -p URL -O /dev/null- ele imprimirá códigos de erro bastante diferentes, caso a URL não esteja disponível, para que você possa configurar um loop para processar sua lista de links e gerar seu status de validade.

Se você estiver finalmente extraindo links de arquivos html, poderá haver alguns problemas sedem casos especiais. Como foi sugerido em uma postagem engraçada que você provavelmente já viu - talvez seja melhor não usar regexps, mas um mecanismo de analisador de html. Um desses analisadores facilmente disponíveis é o navegador somente de texto lynx(disponível em qualquer linux). Isso permite que você despeje instantaneamente a lista de todos os links em um arquivo e extraia os URLs desejados com o grep.

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

No entanto, isso não funcionará na maioria dos arquivos html mutilados ou trechos de texto com links.

r0berts
fonte
-1

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

que incluirá url()e "http"

Roberto Bertó
fonte
3
Como isso é diferente da resposta devnull? Espero que você perceba que o uso de egrepestá obsoleto.
Anthon
Se você tiver uma melhoria em relação a uma resposta existente, consulte o link "compartilhar" abaixo dessa resposta. Veja também as páginas de ajuda
Jeff Schaller
-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

adicione o comando SED como alternativa para armazená-lo no arquivo CSV:

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