Odpowiedzi:
Kluczem do tego, aby zadziałało, jest sed
wykluczenie tego, czego nie chcesz, aby dane wyjściowe, a także określenie tego, czego chcesz.
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
To mówi:
-n
)p
)Ogólnie rzecz biorąc, sed
przechwytujesz grupy za pomocą nawiasów i wyświetlasz to, co przechwytujesz, korzystając z referencji wstecz:
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
wyświetli „pasek”. Jeśli używasz -r
( -E
dla OS X) rozszerzonego wyrażenia regularnego, nie musisz uciekać z nawiasów:
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
Może istnieć do 9 grup przechwytywania i ich referencje. Odwołania wsteczne są ponumerowane w kolejności, w jakiej pojawiają się grupy, ale można ich używać w dowolnej kolejności i można je powtarzać:
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
wyprowadza „słupek a”.
Jeśli masz GNU grep
(może również działać w BSD, w tym OS X):
echo "$string" | grep -Po '\d+'
lub odmiany, takie jak:
echo "$string" | grep -Po '(?<=\D )(\d+)'
Ta -P
opcja włącza wyrażenia regularne zgodne z Perlem. Zobacz man 3 pcrepattern
lub man
3 pcresyntax
.
sed
przykładu, jeśli korzystasz z -r
opcji (lub -E
dla OS X, IIRC), nie musisz uciekać od nawiasów. Różnica polega na tym, że między podstawowymi wyrażeniami regularnymi a rozszerzonymi wyrażeniami regularnymi ( -r
).
Sed ma do dziewięciu zapamiętanych wzorców, ale musisz użyć nawiasów ucieczkowych, aby zapamiętać fragmenty wyrażenia regularnego.
Zobacz tutaj przykłady i więcej szczegółów
sed -e 's/version=\(.+\)/\1/' input.txt
to wciąż wypisze cały input.txt
\+
zamiast +
. I nie rozumiem, dlaczego ludzie używają -e
tylko jednego polecenia sed.
sed -e -n 's/version=\(.+\)/\1/p' input.txt
zobacz: mikeplate.com/2012/05/09/…
sed -E
użycie tak zwanych „nowoczesnych” lub „rozszerzonych” wyrażeń regularnych, które wyglądają znacznie bliżej Perl / Java / JavaScript / Go / cokolwiek innego. (Porównaj z grep -E
lub egrep
.) Domyślna składnia ma dziwne reguły ucieczki i jest uważana za „przestarzałą”. Aby uzyskać więcej informacji na temat różnic między nimi, uruchom man 7 re_format
.
możesz użyć grep
grep -Eow "[0-9]+" file
o
istnieje taka opcja - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, - tylko dopasowanie Dopasuj tylko część pasującego wiersza pasującego WZORZEC
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
Nie wiem, jak możesz wymagać, aby te dwa wyrażenia znajdowały się w jednym wierszu oprócz pipingu z poprzedniego grep (który wciąż nie mógłby działać, jeśli którykolwiek wzorzec pasuje więcej niż jeden raz w wierszu ).
Ta odpowiedź działa z dowolną liczbą grup cyfr. Przykład:
$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Czy jest jakiś sposób, aby powiedzieć sedowi, aby wysyłał tylko przechwycone grupy?
Tak. zastąp cały tekst grupą przechwytywania:
$ echo 'Number 123 inside text' | sed 's/[^0-9]*\([0-9]\{1,\}\)[^0-9]*/\1/'
123
s/[^0-9]* # several non-digits
\([0-9]\{1,\}\) # followed by one or more digits
[^0-9]* # and followed by more non-digits.
/\1/ # gets replaced only by the digits.
Lub z rozszerzoną składnią (mniej cudzysłowów i zezwól na użycie +):
$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123
Aby uniknąć drukowania oryginalnego tekstu, gdy nie ma numeru, użyj:
$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
Aby dopasować kilka liczb (a także je wydrukować):
$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456
Działa to dla dowolnej liczby przebiegów cyfrowych:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Co jest bardzo podobne do polecenia grep:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166
i wzór:
/([\d]+)/
Sed nie rozpoznaje składni „\ d” (skrót). Stosowany powyżej ekwiwalent ascii [0-9]
nie jest dokładnie równoważny. Jedynym alternatywnym rozwiązaniem jest użycie klasy znaków: „[[: digit:]]„.
Wybrana odpowiedź używa takich „klas znaków” do zbudowania rozwiązania:
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
To rozwiązanie działa tylko dla (dokładnie) dwóch serii cyfr.
Oczywiście, ponieważ odpowiedź jest wykonywana wewnątrz powłoki, możemy zdefiniować kilka zmiennych, aby skrócić taką odpowiedź:
$ str='This is a sample 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*/\1 \2/p"
Ale, jak już wyjaśniono, s/…/…/gp
lepsze jest użycie polecenia:
$ str='This is 75577 a sam33ple 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D*/\1 /gp"
75577 33 123 987
Obejmuje to zarówno powtarzające się serie cyfr, jak i pisanie krótkich (er) komend.
Uważam, że wzorzec podany w pytaniu był jedynie przykładowy, a celem było dopasowanie dowolnego wzorca.
Jeśli masz sed z rozszerzeniem GNU pozwalającym na wstawienie nowego wiersza w przestrzeni wzorów, jedną z sugestii jest:
> set string = "This is a sample 123 text and some 987 numbers"
>
> set pattern = "[0-9][0-9]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
123
987
> set pattern = "[a-z][a-z]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
his
is
a
sample
text
and
some
numbers
Te przykłady są z tcsh (tak, wiem, że to zła powłoka) z CYGWIN. (Edycja: Dla bash, usuń set, a spacje wokół =.)
+
, musisz uciec z niego lub skorzystać z -r
opcji ( -E
dla OS X). Możesz także użyć \{1,\}
( -r
lub -E
bez ucieczki).
Zrezygnuj i użyj Perla
Ponieważ sed
go nie tnie, po prostu rzućmy ręcznikiem i użyjmy Perla, przynajmniej LSB, podczas gdy grep
rozszerzenia GNU nie są :-)
Wydrukuj całą pasującą część, nie trzeba dopasowywać grup ani szukać:
cat <<EOS | perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
Wynik:
12
3456
Pojedyncze dopasowanie w wierszu, często uporządkowane pola danych:
cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
Wynik:
1
34
Z lookbehind:
cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
Wiele pól:
cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
Wynik:
1 2
34 56
Wiele dopasowań w wierszu, często nieustrukturyzowane dane:
cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
a1 b2
a34 b56 a78 b90
EOS
Wynik:
1
34 78
Z lookbehind:
cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
Wynik:
1
3478
Próbować
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
Mam to pod cygwin:
$ (echo "asdf"; \
echo "1234"; \
echo "asdf1234adsf1234asdf"; \
echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
1234
1234 1234
1 2 3 4 5 6 7 8 9
$
Nie o to prosił PO (przechwytywanie grup), ale możesz wyodrębnić liczby, używając:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
Daje następujące:
123
987
sed
włączenia rozszerzonych wyrażeń regularnych z-E
flagą.