Wie kann ich eine vollständige URL aus einer halbzufälligen Zeichenfolge extrahieren / analysieren?


11

Ich möchte, dass bash eine vollständige URL (und nur die URL) aus einer zufälligen kurzen Zeichenfolge analysiert / extrahiert.

Beispiele:

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

oder

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

oder

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

oder

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

Ich habe es versucht, cat foo_output | egrep -o "https?://[\w'-\.]*\s"aber das schien nicht zu funktionieren.


Klingt beängstigend, je nachdem, was Sie mit der extrahierten URL machen wollen ...
vonbrand

Antworten:


24

Hast du versucht:

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

stattdessen?

Beachten Sie, dass alles mit einer Zeichenklasse als Literal verstanden wird, sodass das Sprichwort [\w]nicht mit einem Wortzeichen übereinstimmt . Darüber hinaus müssen Sie einem Regex-Metazeichen innerhalb einer Zeichenklasse nicht entkommen, dh, das Sprichwort [\.]ist nicht ganz dasselbe wie [.].


2
[^ ]zu breit ist, sollten Sie andere Zuschnitte auszuschließen (, )möglicherweise Komas, und alle Zeichen , die nicht in URLs sind nicht zulässig.
Stéphane Chazelas

@StephaneChazelas Du hast recht. Ich ging jedoch davon aus, dass der URL ein Leerzeichen vorangestellt und gefolgt wird, außer am Anfang oder am Ende der Zeile.
Devnull

5

URIs sind nicht gut für den Abgleich regulärer Ausdrücke geeignet, wenn sie in natürliche Sprache eingebettet sind. Der aktuelle Stand der Technik ist jedoch John Grubers verbessertes liberales, genaues Regex-Muster für übereinstimmende URLs . Wie derzeit veröffentlicht, lautet die einzeilige Version wie folgt:

(?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 scheint auch einen Kern zu halten hier , obwohl sein Blog - Eintrag hat eine viel bessere Arbeit seinen Testkorpus zu erklären und die Grenzen des regulären Ausdruck.

Wenn Sie den Ausdruck über die Befehlszeile implementieren möchten, sind Sie möglicherweise durch die von Ihnen verwendete Engine für reguläre Ausdrücke oder durch Probleme beim Zitieren von Shell eingeschränkt. Ich habe festgestellt, dass ein Ruby-Skript die beste Option ist, aber Ihr Kilometerstand kann variieren.


2
Bitte fügen Sie den regulären Ausdruck in Ihre Antwort ein, anstatt ihn zu verlinken.
Terdon

@terdon, der vollständige reguläre Ausdruck beträgt etwa 60 Zeilen.
vonbrand

2
@vonbrand Ich weiß, ich habe es gesehen. Wir neigen nur dazu, die Verknüpfung mit externen Ressourcen zu vermeiden. Der Sinn der SE-Sites ist es, ein Wiki zu sein. Was passiert, wenn das von Ihnen verlinkte Blog offline geschaltet wird? Ihre Antwort wird nutzlos. Auf jeden Fall sind 60 Zeilen nicht so viel und es sind nur 60 Zeilen für die Lesbarkeit.
Terdon

2

Das Problem mit übereinstimmenden URLs ist, dass fast alles in einer URL enthalten sein kann:

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

Wie Sie sehen können, über die (gültig) URL enthält $, ?, #, &, ,, .und :. Grundsätzlich können Sie nur sicher sein, dass eine URL kein Leerzeichen enthält. In diesem Sinne können Sie Ihre URLs mit einem so einfachen Muster extrahieren wie:

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

Das \Sentspricht allen Nicht-Leerzeichen in Perl-kompatiblen regulären Ausdrücken (PCREs), -Paktiviert PCREs für grepund -olässt nur das übereinstimmende Segment der Zeile drucken.


0

Ich würde mich verketten, aber ein bisschen anders. Wenn Sie einen Textausschnitt wie Ihren in einer Textdatei namens strings.txt haben, können Sie wie folgt vorgehen:

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

Erläuterung:

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 

Da die URL möglicherweise nicht funktioniert, können Sie zusätzliche Fehlerprüfungen mit Ihrer interessierenden URL durchführen. Beispiel wget -p URL -O /dev/null: Es werden ganz andere Fehlercodes ausgegeben, falls die URL nicht verfügbar ist. Sie können also eine Schleife einrichten, um Ihre Liste der Links zu verarbeiten und ihren Gültigkeitsstatus auszugeben.

Wenn Sie letztendlich Links aus HTML-Dateien extrahieren, kann es sedin besonderen Fällen zu Problemen kommen . Wie in einem lustigen (Beitrag) vorgeschlagen wurde , den Sie wahrscheinlich bereits gesehen haben, ist es möglicherweise am besten, keine regulären Ausdrücke, sondern eine HTML-Parser-Engine zu verwenden. Ein solcher leicht verfügbarer Parser ist der Nur-Text-Browser lynx(verfügbar unter jedem Linux). Auf diese Weise können Sie sofort eine Liste aller Links in einer Datei sichern und dann einfach die gewünschten URLs mit grep extrahieren.

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

Dies funktioniert jedoch nicht bei den meisten verstümmelten HTML-Dateien oder Textausschnitten mit Links.


-1

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

welches beinhaltet url()und "http"


3
Wie unterscheidet sich das von der Antwort von devnull? Ich hoffe, Sie erkennen, dass die Verwendung von egrepveraltet ist.
Anthon

Wenn Sie eine Verbesserung gegenüber einer vorhandenen Antwort haben, können Sie über den Link "Teilen" unter dieser Antwort darauf zurückgreifen. Siehe auch die Hilfeseiten
Jeff Schaller

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

Alternativ können Sie den SED-Befehl anhängen, um ihn in der CSV-Datei zu speichern:

| sed 's/;/<tab>/g' > file.csv
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.