Próbuję użyć sed do czyszczenia linii adresów URL w celu wyodrębnienia samej domeny.
Więc z:
http://www.suepearson.co.uk/product/174/71/3816/
Chcę:
http://www.suepearson.co.uk/
(z ukośnikiem końcowym lub bez niego, to nie ma znaczenia)
Próbowałem:
sed 's|\(http:\/\/.*?\/\).*|\1|'
i (uciekając przed niechcianym kwantyfikatorem)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
ale nie mogę sprawić, żeby nie chciwy kwantyfikator ( ?
) działał, więc zawsze kończy się to dopasowaniem całego łańcucha.
sed -E 's...
. Nadal nie ma niechętnego operatora.cut -d'/' -f1-3
prace.Odpowiedzi:
Ani podstawowy, ani rozszerzony refiks Posix / GNU nie rozpoznaje niepochodnego kwantyfikatora; potrzebujesz późniejszego wyrażenia regularnego. Na szczęście wyrażenie regularne Perla dla tego kontekstu jest dość łatwe do uzyskania:
źródło
-pi -e
.perl
jest wymagane przez POSIXsed
, przy użyciu składni w zasadzie identycznej jak w przypadkused
W tym konkretnym przypadku możesz wykonać zadanie bez użycia wyrażenia chciwego.
Spróbuj tego niechcianego wyrażenia regularnego
[^/]*
zamiast.*?
:źródło
([^&=#]+)=([^&#]*)
. Zdarzają się przypadki, które na pewno nie działają w ten sposób, np. Podczas analizowania adresu URL dla części hosta i nazwy ścieżki z końcowym ukośnikiem, który zakłada się opcjonalnie, aby został wykluczony z przechwytywania:^(http:\/\/.+?)/?$
W przypadku sed zwykle wdrażam niepochodne wyszukiwanie, szukając czegokolwiek oprócz separatora aż do separatora:
Wynik:
to jest:
-n
s/<pattern>/<replace>/p
;
zamiast tego użyj separatora poleceń wyszukiwania,/
aby ułatwić pisanies;<pattern>;<replace>;p
\(
...\)
, później dostępne za pomocą\1
,\2
...http://
[]
,[ab/]
oznaczałoby alboa
albob
albo/
^
w[]
środkachnot
, a następnie wszystko oprócz rzeczy w[]
[^/]
oznacza nic oprócz/
charakteru*
jest powtarzanie poprzedniej grupy, co[^/]*
oznacza znaki oprócz/
.sed -n 's;\(http://[^/]*\)
oznacza wyszukiwanie i zapamiętywanie,http://
po których następują dowolne postacie oprócz/
i pamiętanie tego, co znalazłeś/
więc dodaj kolejną/
na końcu:sed -n 's;\(http://[^/]*\)/'
ale chcemy dopasować resztę wiersza po domenie, więc dodaj.*
\1
) jest domeną, więc zamień dopasowaną linię na rzeczy zapisane w grupie\1
i wydrukuj:sed -n 's;\(http://[^/]*\)/.*;\1;p'
Jeśli chcesz dołączyć ukośnik odwrotny również po domenie, dodaj jeszcze jeden ukośnik w grupie, aby zapamiętać:
wynik:
źródło
sed nie obsługuje operatora „nie chciwego”.
Musisz użyć operatora „[]”, aby wykluczyć „/” z dopasowania.
PS nie ma potrzeby wykonywania odwrotnego ukośnika „/”.
źródło
s/([[:digit:]]\.[[1-9]]*)0*/\1/
oczywiście nie działałby dobrze1.20300
. Ponieważ pierwotne pytanie dotyczyło adresów URL, należy je wymienić w zaakceptowanej odpowiedzi.Symulowanie leniwego (niechcianego) kwantyfikatora w
sed
I wszystkie inne smaki regex!
Znajdowanie pierwszego wystąpienia wyrażenia:
POSIX ERE (przy użyciu
-r
opcji)Regex:
Sed:
Przykład (znalezienie pierwszej sekwencji cyfr) Demo na żywo :
Jak to działa ?
To wyrażenie regularne korzysta z alternacji
|
. Na każdej pozycji silnik próbuje wybrać najdłuższe dopasowanie (jest to standard POSIX, po którym następuje również kilka innych silników), co oznacza, że działa tak.
długo, aż zostanie znalezione dopasowanie([0-9]+).*
. Ale porządek też jest ważny.Ponieważ ustawiono flagę globalną, silnik próbuje kontynuować dopasowywanie znak po znaku do końca ciągu wejściowego lub naszego celu. Gdy tylko pierwsza i jedyna grupa przechwytująca lewej strony naprzemiennej zostanie dopasowana,
(EXPRESSION)
reszta linii jest natychmiast zużywana.*
. Teraz utrzymujemy naszą wartość w pierwszej grupie przechwytywania.POSIX BRE
Regex:
Sed:
Przykład (znalezienie pierwszej sekwencji cyfr):
Ten jest jak wersja ERE, ale nie wymaga zmiany. To wszystko. Na każdej pozycji silnik próbuje dopasować cyfrę.
Jeśli zostanie znalezione, inne kolejne cyfry zostaną zużyte i przechwycone, a reszta linii zostanie dopasowana natychmiast, w przeciwnym razie
*
oznacza więcej lub zero , pomija drugą grupę przechwytywania\(\([0-9]\{1,\}\).*\)*
i dociera do kropki.
odpowiadającej jednemu znakowi, a proces ten jest kontynuowany.Znajdowanie pierwszego wystąpienia wyrażenia rozdzielanego :
To podejście będzie pasować do pierwszego wystąpienia rozdzielanego łańcucha. Możemy to nazwać blokiem łańcucha.
Ciąg wejściowy:
-EDE:
end
-SDE:
start
Wynik:
Pierwsze wyrażenie regularne
\(end\).*
dopasowuje i przechwytuje ogranicznik pierwszego końcaend
i podstawniki wszystkie pasują do ostatnio przechwyconych znaków, które są ogranicznikiem końca. Na tym etapie nasza produkcja jest:foobar start block #1 end
.Następnie wynik jest przekazywany do drugiego wyrażenia regularnego,
\(\(start.*\)*.\)*
który jest taki sam jak wersja POSIX BRE powyżej. Dopasowuje pojedynczy znak, jeśli ogranicznik początkowystart
nie jest dopasowany, w przeciwnym razie dopasowuje i przechwytuje ogranicznik początkowy i dopasowuje pozostałe znaki.Bezpośrednio odpowiadając na twoje pytanie
Stosując podejście nr 2 (wyrażenie rozdzielane), powinieneś wybrać dwa odpowiednie wyrażenia:
EDE:
[^:/]\/
SDE:
http:
Stosowanie:
Wynik:
Uwaga: nie będzie działać z identycznymi ogranicznikami.
źródło
sed
wszystkich innych silnikach zgodnych z tą samą standardową kolejnością ma znaczenie, jeśli chodzi o równość. Więcecho 'foo 1' | sed -r 's/.|([0-9]+).*/\1/g'
nie pasuje, aleecho 'foo 1' | sed -r 's/([0-9]+).*|./\1/g'
ma.Nie chciwe rozwiązanie dla więcej niż jednego znaku
Ten wątek jest naprawdę stary, ale zakładam, że ludzie nadal go potrzebują. Powiedzmy, że chcesz zabić wszystko do pierwszego wystąpienia
HELLO
. Nie możesz powiedzieć[^HELLO]
...Dobre rozwiązanie składa się z dwóch etapów, zakładając, że możesz zaoszczędzić unikalne słowo, którego nie oczekujesz, powiedzmy
top_sekrit
.W takim przypadku możemy:
Oczywiście przy prostszym wprowadzeniu można użyć mniejszego słowa, a może nawet jednego znaku.
HTH!
źródło
`
użyłbym<$$>
(ponieważ$$
rozwija się do twojego identyfikatora procesu w powłoce, chociaż będziesz musiał użyć podwójnych cudzysłowów zamiast pojedynczych cudzysłowów, i to może uszkodzić inne części wyrażenia regularnego) lub, jeśli dostępny jest Unicode, coś podobnego<∈∋>
.perl
lubpython
innego języka.perl
robi to w mniej delikatny sposób w jednym wierszu ...sed - nie chciwe dopasowanie przez Christopha Siegharta
Sztuką, aby uzyskać nie chciwe dopasowanie w sed, jest dopasowanie wszystkich znaków oprócz tej, która kończy dopasowanie. Wiem, że to oczywiste, ale zmarnowałem na to cenne minuty, a skrypty powłoki powinny być w końcu szybkie i łatwe. Na wypadek, gdyby ktoś inny mógł go potrzebować:
Chciwe dopasowanie
Nie chciwe dopasowanie
źródło
Można to zrobić za pomocą cut:
źródło
innym sposobem, nie używając wyrażenia regularnego, jest użycie metody pola / separator np
źródło
sed
na pewno ma swoje miejsce, ale to nie jeden z nich!Jak zauważył Dee: po prostu użyj
cut
. W tym przypadku jest to znacznie prostsze i znacznie bezpieczniejsze. Oto przykład, w którym wyodrębniamy różne składniki z adresu URL przy użyciu składni Bash:daje Ci:
Jak widać, jest to bardziej elastyczne podejście.
(wszystkie podziękowania dla Dee)
źródło
źródło
sed -E interpretuje wyrażenia regularne jako rozszerzone (nowoczesne) wyrażenia regularne
Aktualizacja: -E na MacOS X, -r w GNU sed.
źródło
-E
jest unikalny dla BSD,sed
a zatem OS X. Linki do stron podręcznika man.-r
wprowadza rozszerzone wyrażenia regularne do GNU,sed
jak zauważono w poprawce @ stephancheg. Uważaj podczas używania polecenia o znanej zmienności w różnych dystrybucjach nix. Nauczyłem się tego na własnej skórze.-r
Opcja GNU sed zmienia tylko reguły zmiany znaczenia, zgodnieAppendix A Extended regular expressions
z plikiem informacyjnym i kilkoma szybkimi testami; tak naprawdę nie dodaje niepochodnego kwalifikatora (GNU sed version 4.2.1
przynajmniej od tego.)-E
przez pewien czas uznawana była za nieudokumentowaną opcję, ale w wersji 4.2.2.177 dokumentacja została zaktualizowana, aby to odzwierciedlić, więc teraz-E
jest w porządku dla obu.Nadal istnieje nadzieja na rozwiązanie tego problemu za pomocą czystego (GNU) sed. Mimo że nie jest to ogólne rozwiązanie, w niektórych przypadkach można użyć „pętli”, aby wyeliminować wszystkie niepotrzebne części łańcucha:
Jedynym problemem jest to, że wycina również ostatni znak separatora ('/'), ale jeśli naprawdę go potrzebujesz, możesz po prostu odłożyć go z powrotem po zakończeniu pętli, po prostu dodaj to dodatkowe polecenie na końcu poprzedniego wiersz poleceń:
źródło
Ponieważ wyraźnie stwierdziłeś, że próbujesz użyć sed (zamiast perl, cut itp.), Spróbuj pogrupować. To omija niechciany identyfikator potencjalnie nierozpoznany. Pierwszą grupą jest protokół (tj. „Http: //”, „https: //”, „tcp: //” itp.). Druga grupa to domena:
Jeśli nie znasz grupowania, zacznij tutaj .
źródło
Zdaję sobie sprawę, że to stary wpis, ale ktoś może uznać go za przydatny. Ponieważ pełna nazwa domeny nie może przekraczać całkowitej długości 253 znaków, zamień. * Na. \ {1, 255 \}
źródło
Oto jak solidnie wykonywać niechciane dopasowanie ciągów wieloznakowych za pomocą sed. Powiedzmy, że chcemy zmienić każdy
foo...bar
się<foo...bar>
więc na przykład tego wejścia:powinien stać się tym wyjściem:
Aby to zrobić, przekonwertuj foo i pasek na pojedyncze znaki, a następnie użyj negacji tych znaków między nimi:
W powyższym:
s/@/@A/g; s/{/@B/g; s/}/@C/g
konwertuje{
i}
na łańcuchy znaków zastępczych, które nie mogą istnieć w danych wejściowych, więc te znaki są wtedy dostępne do konwersjifoo
ibar
.s/foo/{/g; s/bar/}/g
współczynnik konwersjifoo
ibar
do{
i}
odpowiednios/{[^{}]*}/<&>/g
wykonuje op chcemy - konwersjafoo...bar
do<foo...bar>
s/}/bar/g; s/{/foo/g
konwertuje{
i}
wraca dofoo
ibar
.s/@C/}/g; s/@B/{/g; s/@A/@/g
konwertuje łańcuchy znaków zastępczych z powrotem na ich oryginalne znaki.Zauważ, że powyższe nie polega na tym, że żaden konkretny ciąg nie jest obecny na wejściu, ponieważ produkuje takie ciągi w pierwszym kroku, ani nie przejmuje się tym, które wystąpienie określonego wyrażenia regularnego chcesz dopasować, ponieważ możesz użyć
{[^{}]*}
tyle razy, ile to konieczne. w wyrażeniu, aby wyodrębnić właściwe dopasowanie i / lub operatorem dopasowania numerycznego seds, np. aby zastąpić tylko 2 wystąpienie:źródło
Nie widziałem jeszcze tej odpowiedzi, więc możesz to zrobić za pomocą
vi
lubvim
:To powoduje
vi
:%s
globalne podstawienie (końcoweg
), powstrzymuje się od zgłaszania błędu, jeśli wzorzec nie zostanie znaleziony (e
), a następnie zapisuje wynikowe zmiany na dysku i kończy pracę. W&>/dev/null
zapobiega GUI z krótko migać na ekranie, co może być uciążliwe.I jak za pomocą
vi
czasami bardzo skomplikowane regexes, ponieważ (1) Perl jestmartwyumieranie, (2) Vim posiada bardzo zaawansowany silnik regex, oraz (3) Jestem już zaznajomiony zvi
regexes w moim edycji użytkowania z dnia na dzień dokumentyźródło
nie przejmuj się, mam to na innym forum :)
źródło
/home/one/two/three/
jeśli dodasz inny/
jak/home/one/two/three/four/myfile.txt
was łapczywie dopasowaćfour
także:/home/one/two/three/four
, pytanie o zakaz chciwysed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
też działaźródło
Oto coś, co możesz zrobić, stosując dwustopniowe podejście i awk:
Mam nadzieję, że to pomaga!
źródło
Kolejna wersja sed:
Pasuje
/
po nim znak alfanumeryczny (więc nie kolejny ukośnik), a także reszta znaków do końca linii. Następnie zastępuje go niczym (tzn. Usuwa.)źródło
"[[:alnum:]]"
, nie"[:alphanum:]"
.