Widzę wiele przykładów i stron podręcznika, jak wykonywać takie czynności, jak wyszukiwanie i zamiana za pomocą sed, awk lub gawk.
Ale w moim przypadku mam wyrażenie regularne, które chcę uruchomić w pliku tekstowym, aby wyodrębnić określoną wartość. Nie chcę wyszukiwać i zamieniać. To się nazywa z bash. Posłużmy się przykładem:
Przykładowe wyrażenie regularne:
.*abc([0-9]+)xyz.*
Przykładowy plik wejściowy:
a
b
c
abc12345xyz
a
b
c
Brzmi to prosto, ale nie potrafię poprawnie wywołać sed / awk / gawk. To, co miałem nadzieję zrobić, to z poziomu mojego skryptu bash:
myvalue=$( sed <...something...> input.txt )
Rzeczy, które próbowałem, obejmują:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Odpowiedzi:
Mój
sed
(Mac OS X) nie działał z+
. Spróbowałem*
zamiast tego i dodałemp
tag do drukowania dopasowania:Aby dopasować co najmniej jeden znak numeryczny bez
+
, użyłbym:źródło
+
i wtedy to zadziałało:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Możesz do tego użyć seda
-n
nie drukuj wynikowej linii-r
To sprawia, że nie masz ucieczki przed grupami przechwytującymi()
.\1
dopasowanie grupy przechwytywania/g
globalne dopasowanie/p
wydrukuj wynikNapisałem dla siebie narzędzie, które to ułatwia
źródło
Używam,
perl
żeby sobie to ułatwić. na przykładSpowoduje to uruchomienie Perla,
-n
opcja instruuje Perl, aby czytał po jednym wierszu na raz z STDIN i wykonywał kod.-e
Opcja określa instrukcje do uruchomienia.Instrukcja uruchamia wyrażenie regularne w przeczytanym wierszu i jeśli pasuje, wypisuje zawartość pierwszego zestawu nawiasów (
$1
).Możesz to zrobić, jeśli na końcu pojawi się wiele nazw plików. na przykład
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
źródło
Jeśli twoja wersja
grep
obsługuje to, możesz użyć-o
opcji drukowania tylko części dowolnego wiersza, która pasuje do twojego wyrażenia regularnego.Jeśli nie, oto najlepsze,
sed
jakie mogłem wymyślić:... który usuwa / pomija bez cyfr, a dla pozostałych wierszy usuwa wszystkie początkowe i końcowe znaki niebędące cyframi. (Domyślam się tylko, że twoim zamiarem jest wyodrębnienie liczby z każdego wiersza, który zawiera jeden).
Problem z czymś takim:
.... lub
... jest to, że
sed
obsługuje tylko "zachłanne" dopasowanie ... więc pierwsza. * będzie pasować do reszty linii. O ile nie możemy użyć zanegowanej klasy znaków, aby osiągnąć niechciwe dopasowanie ... lub wersjęsed
z kompatybilnymi z Perl lub innymi rozszerzeniami do jej wyrażeń regularnych, nie możemy wyodrębnić dokładnego dopasowania wzorca z przestrzeni wzorców (linia ).źródło
sed
polecenia w ten sposób:sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! Próbowałem to zrobićsed
i walczyłem z moją potrzebą znalezienia wielu dopasowań na niektórych liniach. Moje rozwiązanie to stackoverflow.com/a/58308239/117471Możesz użyć
awk
z,match()
aby uzyskać dostęp do przechwyconej grupy:To próbuje dopasować wzorzec
abc[0-9]+xyz
. Jeśli to zrobi, przechowuje swoje wycinki w tablicymatches
, której pierwszym elementem jest blok[0-9]+
. Ponieważmatch()
zwraca pozycję znaku lub indeks miejsca, w którym zaczyna się ten podciąg (1, jeśli zaczyna się na początku ciągu) , wyzwalaprint
akcję.Dzięki
grep
możesz użyć patrzenia wstecz i przewidywania:Sprawdza to wzór
[0-9]+
, gdy zachodzi wewnątrzabc
ixyz
i drukuje tylko cyfry.źródło
perl to najczystsza składnia, ale jeśli nie masz perla (rozumiem, że nie zawsze tam jest), jedynym sposobem użycia gawk i składników wyrażenia regularnego jest użycie funkcji gensub.
wyjście z przykładowego pliku wejściowego będzie
Uwaga: gensub zamienia całe wyrażenie regularne (między //), więc musisz wstawić. * Przed i po ([0-9] +), aby pozbyć się tekstu przed i po liczbie w podstawieniu.
źródło
match()
aby uzyskać dostęp do przechwyconych grup. Zobacz moją odpowiedź na to.Jeśli chcesz zaznaczyć linie, usuń niepotrzebne fragmenty:
Zasadniczo wybiera żądane linie,
egrep
a następnie używased
do usunięcia bitów przed i po liczbie.Możesz to zobaczyć w akcji tutaj:
Aktualizacja: oczywiście, jeśli twoja rzeczywista sytuacja jest bardziej złożona, RE będą musiały mnie zmodyfikować. Na przykład, jeśli zawsze miałeś jedną liczbę ukrytą w obrębie zera lub większej liczby liczb nienumerycznych na początku i na końcu:
źródło
Przypadek OP nie określa, że może istnieć wiele dopasowań w jednym wierszu, ale dla ruchu Google dodam również przykład.
Ponieważ potrzebą OP jest wyodrębnienie grupy ze wzoru, użycie
grep -o
będzie wymagało 2 przejść. Ale nadal uważam, że jest to najbardziej intuicyjny sposób wykonania pracy.Ponieważ czas procesora jest w zasadzie wolny, ale czytelność dla człowieka jest bezcenna, mam tendencję do refaktoryzacji kodu w oparciu o pytanie „za rok od teraz, co myślę, że to robi?” W rzeczywistości w przypadku kodu, który zamierzam udostępnić publicznie lub swojemu zespołowi, otworzę nawet,
man grep
aby dowiedzieć się, jakie są długie opcje i je zastąpić. Tak jak to:grep --only-matching --extended-regexp
źródło
możesz to zrobić z muszlą
źródło
Dla awk. Użyłbym następującego skryptu:
źródło
([0-9+])
, to wyświetla całą linię.źródło