Ich versuche, sed zu verwenden, um URL-Zeilen zu bereinigen und nur die Domain zu extrahieren.
Also von:
http://www.suepearson.co.uk/product/174/71/3816/
Ich möchte:
http://www.suepearson.co.uk/
(entweder mit oder ohne den abschließenden Schrägstrich, es spielt keine Rolle)
Ich habe versucht:
sed 's|\(http:\/\/.*?\/\).*|\1|'
und (dem nicht gierigen Quantifizierer entkommen)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
Aber ich kann nicht scheinen, dass der nicht gierige Quantifizierer ( ?
) funktioniert, so dass er immer mit der gesamten Zeichenfolge übereinstimmt.
sed -E 's...
. Trotzdem kein widerstrebender Bediener.cut -d'/' -f1-3
Arbeiten.Antworten:
Weder der grundlegende noch der erweiterte Posix / GNU-Regex erkennen den nicht gierigen Quantifizierer. Sie benötigen eine spätere Regex. Glücklicherweise ist Perl Regex für diesen Kontext ziemlich einfach zu bekommen:
quelle
-pi -e
.perl
ist erforderlich von POSIXsed
, mit einer Syntax, die im Grunde identisch mit der vonsed
In diesem speziellen Fall können Sie die Arbeit erledigen, ohne einen nicht gierigen regulären Ausdruck zu verwenden.
Versuchen Sie diesen nicht gierigen regulären Ausdruck
[^/]*
anstelle von.*?
:quelle
([^&=#]+)=([^&#]*)
. Es gibt Fälle, die auf diese Weise nicht sicher funktionieren, z. B. wenn die URL für ihren Host-Teil und den Pfadnamen analysiert wird, wobei der endgültige Schrägstrich als optional für die Erfassung ausgeschlossen gilt:^(http:\/\/.+?)/?$
Mit sed implementiere ich normalerweise eine nicht gierige Suche, indem ich bis zum Trennzeichen nach etwas anderem als dem Trennzeichen suche:
Ausgabe:
das ist:
-n
s/<pattern>/<replace>/p
;
stattdessen das Suchbefehlstrennzeichen/
, um die Eingabe zu vereinfachens;<pattern>;<replace>;p
\(
...\)
, später zugänglich mit\1
,\2
...http://
[]
,[ab/]
würde bedeuten , entwedera
oderb
oder/
^
in[]
Mittelnnot
, also gefolgt von irgendetwas anderem als der Sache in der[]
[^/]
bedeutet nichts außer/
Charakter*
ist die vorherige Gruppe zu wiederholen,[^/]*
bedeutet also Zeichen außer/
.sed -n 's;\(http://[^/]*\)
bedeutet Suchen und Erinnern,http://
gefolgt von Zeichen, außer/
und merken Sie sich, was Sie gefunden haben/
und fügen Sie/
am Ende eine weitere hinzu.sed -n 's;\(http://[^/]*\)/'
Wir möchten jedoch den Rest der Zeile nach dem Hinzufügen der Domain abgleichen.*
\1
) gespeicherte Übereinstimmung die Domäne. Ersetzen Sie also die übereinstimmende Zeile durch in der Gruppe gespeicherte Daten\1
und drucken Sie:sed -n 's;\(http://[^/]*\)/.*;\1;p'
Wenn Sie auch nach der Domain einen Backslash einfügen möchten, fügen Sie der Gruppe einen weiteren Backslash hinzu, um Folgendes zu beachten:
Ausgabe:
quelle
sed unterstützt keinen "nicht gierigen" Operator.
Sie müssen den Operator "[]" verwenden, um "/" von der Übereinstimmung auszuschließen.
PS Es ist kein Backslash "/" erforderlich.
quelle
s/([[:digit:]]\.[[1-9]]*)0*/\1/
würde offensichtlich nicht gut funktionieren für1.20300
. Da es sich bei der ursprünglichen Frage jedoch um URLs handelte, sollten diese in der akzeptierten Antwort erwähnt werden.Simulation eines faulen (nicht gierigen) Quantifizierers in
sed
Und alle anderen Regex-Aromen!
Erstes Auftreten eines Ausdrucks finden:
POSIX ERE (mit
-r
Option)Regex:
Sed:
Beispiel (erste Ziffernfolge finden) Live-Demo :
Wie funktioniert es ?
Dieser Regex profitiert von einer Abwechslung
|
. An jeder Position versucht die Engine, die längste Übereinstimmung auszuwählen (dies ist ein POSIX-Standard, dem auch einige andere Engines folgen), was bedeutet, dass sie so lange.
läuft, bis eine Übereinstimmung für gefunden wird([0-9]+).*
. Ordnung ist aber auch wichtig.Da das globale Flag gesetzt ist, versucht die Engine, Zeichen für Zeichen bis zum Ende der Eingabezeichenfolge oder unseres Ziels weiter abzugleichen. Sobald die erste und einzige Erfassungsgruppe der linken Seite des Wechsels übereinstimmt, wird auch der
(EXPRESSION)
Rest der Leitung sofort verbraucht.*
. Wir halten jetzt unseren Wert in der ersten Erfassungsgruppe.POSIX BRE
Regex:
Sed:
Beispiel (erste Ziffernfolge finden):
Dieser ist wie die ERE-Version, jedoch ohne Wechsel. Das ist alles. An jeder einzelnen Position versucht der Motor, eine Ziffer zu finden.
Wenn festgestellt wird, werden andere Ziffern folgende verbraucht und eingefangen und der Rest der Leitung angepasst ist sofort ansonsten da
*
Mittel mehr oder Null ist es über die zweite Erfassungsgruppe überspringt\(\([0-9]\{1,\}\).*\)*
und kommt an einem Punkt.
ein einzelnes Zeichen zu entsprechen , und dieser Prozess wird fortgesetzt.Erstes Auftreten eines begrenzten Ausdrucks finden:
Dieser Ansatz entspricht dem allerersten Auftreten einer durch Trennzeichen getrennten Zeichenfolge. Wir können es einen Stringblock nennen.
Eingabezeichenfolge:
-EDE:
end
-SDE:
start
Ausgabe:
Der erste reguläre Ausdruck
\(end\).*
stimmt mit dem Trennzeichen für das erste Ende überein und erfasst es. Ersetztend
alle Übereinstimmungen durch die zuletzt erfassten Zeichen, die das Endtrennzeichen sind. Zu diesem Zeitpunkt ist unser Output :foobar start block #1 end
.Dann wird das Ergebnis an den zweiten regulären Ausdruck übergeben
\(\(start.*\)*.\)*
, der der obigen POSIX BRE-Version entspricht. Es stimmt mit einem einzelnen Zeichen überein, wenn das Starttrennzeichenstart
nicht übereinstimmt. Andernfalls stimmt es mit dem Starttrennzeichen überein und erfasst es und stimmt mit den übrigen Zeichen überein.Beantworten Sie Ihre Frage direkt
Unter Verwendung von Ansatz 2 (begrenzter Ausdruck) sollten Sie zwei geeignete Ausdrücke auswählen:
EDE:
[^:/]\/
SDE:
http:
Verwendungszweck:
Ausgabe:
Hinweis: Dies funktioniert nicht mit identischen Trennzeichen.
quelle
sed
und alle anderen Motoren, die der gleichen Standardreihenfolge folgen , spielen jedoch eine Rolle, wenn es um Gleichheit geht. Hatecho 'foo 1' | sed -r 's/.|([0-9]+).*/\1/g'
also kein Match,echo 'foo 1' | sed -r 's/([0-9]+).*|./\1/g'
tut es aber .Nicht gierige Lösung für mehr als ein einzelnes Zeichen
Dieser Thread ist wirklich alt, aber ich gehe davon aus, dass die Leute ihn noch brauchen. Nehmen wir an, Sie möchten alles bis zum ersten Auftreten von töten
HELLO
. Das kann man nicht sagen[^HELLO]
...Eine gute Lösung besteht also aus zwei Schritten, vorausgesetzt, Sie können ein eindeutiges Wort sparen, das Sie beispielsweise in der Eingabe nicht erwarten
top_sekrit
.In diesem Fall können wir:
Natürlich könnten Sie mit einer einfacheren Eingabe ein kleineres Wort oder sogar ein einzelnes Zeichen verwenden.
HTH!
quelle
`
würde ich stattdessen verwenden<$$>
(da$$
sich Ihre Prozess-ID in der Shell erweitert, obwohl Sie doppelte Anführungszeichen anstelle von einfachen Anführungszeichen verwenden müssten, und das könnte andere Teile Ihres regulären Ausdrucks beschädigen) oder, falls Unicode verfügbar ist, so etwas wie<∈∋>
.perl
oderpython
oder einer anderen Sprache statt.perl
macht dies auf eine weniger fragile Weise in einer einzigen Zeile ...sed - nicht gieriges Matching von Christoph Sieghart
Der Trick, um in sed eine nicht gierige Übereinstimmung zu erzielen, besteht darin, alle Zeichen mit Ausnahme derjenigen zu finden, die die Übereinstimmung beenden. Ich weiß, ein Kinderspiel, aber ich habe wertvolle Minuten damit verschwendet, und Shell-Skripte sollten schließlich schnell und einfach sein. Für den Fall, dass jemand anderes es braucht:
Gieriges Matching
Nicht gieriges Matching
quelle
Dies kann mit cut erfolgen:
quelle
Eine andere Möglichkeit, keinen regulären Ausdruck zu verwenden, besteht darin, die Methode "Felder / Trennzeichen" zu verwenden, z
quelle
sed
sicherlich hat seinen Platz aber dieser nicht keiner von ihnen!Wie Dee betont hat: Verwenden Sie einfach
cut
. In diesem Fall ist es viel einfacher und viel sicherer. Hier ist ein Beispiel, in dem wir verschiedene Komponenten mithilfe der Bash-Syntax aus der URL extrahieren:gibt Ihnen:
Wie Sie sehen, ist dies ein viel flexiblerer Ansatz.
(alle Gutschrift an Dee)
quelle
quelle
sed -E interpretiert reguläre Ausdrücke als erweiterte (moderne) reguläre Ausdrücke
Update: -E unter MacOS X, -r in GNU sed.
quelle
-E
ist BSDsed
und damit OS X einzigartig. Links zu Manpages.-r
bringt erweiterte reguläre Ausdrücke zu GNU,sed
wie in der Korrektur von @ stephancheg angegeben. Seien Sie vorsichtig, wenn Sie einen Befehl mit bekannter Variabilität über Nix-Verteilungen verwenden. Das habe ich auf die harte Tour gelernt.-r
Option von GNU sed ändert nur die Escape-Regeln gemäßAppendix A Extended regular expressions
der Info-Datei und einigen Schnelltests. es fügt eigentlich kein nichtGNU sed version 4.2.1
-E
für eine Weile als undokumentierte Option erkannt , aber in Version 4.2.2.177 wurde die Dokumentation aktualisiert, um dies widerzuspiegeln. Daher-E
ist dies für beide jetzt in Ordnung.Es besteht immer noch die Hoffnung, dies mit reinem (GNU) sed zu lösen. Obwohl dies in einigen Fällen keine generische Lösung ist, können Sie "Schleifen" verwenden, um alle unnötigen Teile der Zeichenfolge wie folgt zu entfernen:
Das einzige Problem hierbei ist, dass auch das letzte Trennzeichen ('/') abgeschnitten wird. Wenn Sie es jedoch wirklich benötigen, können Sie es nach Beendigung der "Schleife" einfach wieder zurücksetzen. Fügen Sie einfach diesen zusätzlichen Befehl am Ende des vorherigen hinzu Befehlszeile:
quelle
Versuchen Sie eine Gruppierung, da Sie ausdrücklich angegeben haben, dass Sie versuchen, sed zu verwenden (anstelle von Perl, Cut usw.). Dies umgeht die nicht gierige Kennung, die möglicherweise nicht erkannt wird. Die erste Gruppe ist das Protokoll (dh 'http: //', 'https: //', 'tcp: //' usw.). Die zweite Gruppe ist die Domäne:
Wenn Sie mit Gruppierung nicht vertraut sind, beginnen Sie hier .
quelle
Mir ist klar, dass dies ein alter Eintrag ist, aber jemand kann ihn nützlich finden. Da der vollständige Domainname eine Gesamtlänge von 253 Zeichen nicht überschreiten darf, ersetzen Sie. * Durch. \ {1, 255 \}
quelle
Auf diese Weise können Sie mit sed einen nicht gierigen Abgleich von Zeichenfolgen mit mehreren Zeichen durchführen. Nehmen wir an, Sie möchten jeden ändern
foo...bar
,<foo...bar>
zum Beispiel diese Eingabe:sollte diese Ausgabe werden:
Dazu konvertieren Sie foo und bar in einzelne Zeichen und verwenden dann die Negation dieser Zeichen zwischen ihnen:
In obigem:
s/@/@A/g; s/{/@B/g; s/}/@C/g
konvertiert{
und}
in Platzhalterzeichenfolgen, die in der Eingabe nicht vorhanden sein können, sodass diese Zeichen dann zum Konvertierenfoo
undbar
in verfügbar sind .s/foo/{/g; s/bar/}/g
konvertiertfoo
undbar
zu{
und}
jeweilss/{[^{}]*}/<&>/g
führt die Operation aus, die wir wollen - konvertierenfoo...bar
zu<foo...bar>
s/}/bar/g; s/{/foo/g
konvertiert{
und}
zurück zufoo
undbar
.s/@C/}/g; s/@B/{/g; s/@A/@/g
konvertiert die Platzhalterzeichenfolgen zurück in ihre ursprünglichen Zeichen.Beachten Sie, dass das oben Gesagte nicht davon abhängt, dass eine bestimmte Zeichenfolge nicht in der Eingabe vorhanden ist, da diese Zeichenfolgen im ersten Schritt hergestellt werden, und es auch nicht wichtig ist, mit welchem Vorkommen eines bestimmten regulären Ausdrucks Sie übereinstimmen möchten, da Sie ihn
{[^{}]*}
so oft wie nötig verwenden können im Ausdruck, um die gewünschte tatsächliche Übereinstimmung und / oder mit dem numerischen Übereinstimmungsoperator seds zu isolieren, z. B. um nur das zweite Vorkommen zu ersetzen:quelle
Haben Sie diese Antwort noch nicht gesehen? So können Sie dies mit
vi
oder tunvim
:Dadurch wird die
vi
:%s
Ersetzung global ausgeführt (nachfolgendg
), es wird kein Fehlere
ausgelöst, wenn das Muster nicht gefunden wird ( ), und die resultierenden Änderungen werden auf der Festplatte gespeichert und beendet. Die&>/dev/null
verhindert , dass die GUI von kurz auf dem Bildschirm blinkt, die lästig sein kann.Ich mag mit einem
vi
super kompliziert Regexes manchmal, weil (1) perl isttotSterben, (2) vim hat einen sehr fortschrittlichen Regex - Engine, und (3) Ich bin bereits vertraut mitvi
regulären Ausdrücken in meiner Tag zu Tag Nutzung Bearbeitung Unterlagen.quelle
Mach dir keine Sorgen, ich habe es in einem anderen Forum bekommen :)
quelle
/home/one/two/three/
Wenn Sie eine andere hinzufügen ,/
wie/home/one/two/three/four/myfile.txt
Sie Gierig passenfour
auch:/home/one/two/three/four
die Frage ist über nicht-gierigsed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
funktioniert auchquelle
Folgendes können Sie mit einem zweistufigen Ansatz und awk tun:
Ich hoffe, das hilft!
quelle
Eine andere sed Version:
Es werden Übereinstimmungen
/
gefolgt von einem alphanumerischen Zeichen (also kein weiterer Schrägstrich) sowie den restlichen Zeichen bis zum Ende der Zeile angezeigt. Danach ersetzt es es durch nichts (dh löscht es.)quelle
"[[:alnum:]]"
nicht sein"[:alphanum:]"
.