Odpowiedzi:
2 rzeczy:
-o
opcji, więc drukowane jest tylko dopasowanie (zamiast całej linii)-P
skorzystać z wyrażeń regularnych Perla, które zawierają przydatne elementy, takie jak Spójrz przed siebie (?= )
i Spójrz za nimi (?<= )
, które szukają części, ale tak naprawdę nie pasują i nie drukują ich.Jeśli chcesz dopasować tylko część wewnątrz parensis:
grep -oP '(?<=\/\()\w(?=\).+\/)' myfile.txt
jeśli plik zawiera żądło /(a)5667/
, grep wypisze „a”, ponieważ:
/(
zostały znalezione przez \/\(
, ale ponieważ znajdują się w tyle, (?<= )
nie są zgłaszanea
jest dopasowany \w
i dlatego jest drukowany (z powodu -o
))5667/
znajdują się b < \).+\/
, ale ponieważ patrzą w przyszłość, (?= )
nie są zgłaszaneUżyj -o
opcji w grep
.
Na przykład:
$ echo "foobarbaz" | grep -o 'b[aeiou]r'
bar
Jeśli chcesz tylko tego, co jest w nawiasach, potrzebujesz czegoś, co obsługuje przechwytywanie pod dopasowań (nazwane lub numerowane grupy przechwytywania). Nie sądzę, że grep lub egrep mogą to zrobić, perl i sed mogą. Na przykład za pomocą perla:
Jeśli plik o nazwie foo ma linię, wygląda to następująco:
/adsdds /
I robisz:
perl -nle 'print $1 if /\/(\w).+\//' foo
Litera a jest zwracana. To może nie być to, czego chcesz. Jeśli powiesz nam, co próbujesz dopasować, możesz uzyskać lepszą pomoc. 1 USD to kwota uchwycona w pierwszym zestawie nawiasów. 2 USD będzie drugim zestawem itp.
Ponieważ otagowałeś swoje pytanie jako bash oprócz powłoki , istnieje inne rozwiązanie oprócz grep :
Bash ma swój własny silnik wyrażeń regularnych od wersji 3.0, wykorzystujący =~
operator, podobnie jak Perl.
teraz, biorąc pod uwagę następujący kod:
#!/bin/bash
DATA="test <Lane>8</Lane>"
if [[ "$DATA" =~ \<Lane\>([[:digit:]]+)\<\/Lane\> ]]; then
echo $BASH_REMATCH
echo ${BASH_REMATCH[1]}
fi
bash
nie tylko sh
w celu uzyskania wszystkich rozszerzeń$BASH_REMATCH
da cały ciąg zgodny z całym wyrażeniem regularnym, więc <Lane>8</Lane>
${BASH_REMATCH[1]}
da część dopasowaną przez 1. grupę, a więc tylko 8
>
symbol do zupełnie innych celów), które zostały wyrzucone przez oprogramowanie SANSparallel do szybkiego dostosowywania na dużą skalę . Oczywiście oba formaty są przeplatane bez przeplotu. Dlatego nie można wrzucić do tego jakiejś standardowej biblioteki XML. I używam wyrażenia regularnego Bash w tym miejscu kodu, ponieważ muszę tylko wyodrębnić kilka danych, a 2 wyrażenia regularne wykonują dla mnie zadanie znacznie lepiej niż pisanie dedykowanego analizatora składni dla tego bałaganu. #LifeInBioinformatics
Zakładając, że plik zawiera:
$ cat file
Text-here>xyz</more text
I chcesz znaków między >
i </
, możesz użyć albo:
grep grep -oP '.*\K(?<=>)\w+(?=<\/)' file
sed sed -nE 's:^.*>(\w+)</.*$:\1:p' file
awk awk '{print(gensub("^.*>(\\w+)</.*$","\\1","g"))}' file
perl perl -nle 'print $1 if />(\w+)<\//' file
Wszystko wypisze ciąg „xyz”.
Jeśli chcesz uchwycić cyfry tej linii:
$ cat file
Text-<here>1234</text>-ends
grep grep -oP '.*\K(?<=>)[0-9]+(?=<\/)' file
sed sed -E 's:^.*>([0-9]+)</.*$:\1:' file
awk awk '{print(gensub(".*>([0-9]+)</.*","\\1","g"))}' file
perl perl -nle 'print $1 if />([0-9]+)<\//' file
echo 'Text-<here>1234</text>-ends' | sed -E 's|.*>([[:digit:]]+)<.*|\1|'
. W niektórych przypadkach (np. [0-9]
Vs. [[:digit:]]
) nie pomagają one w czytelności, w innych myślę, że tak (np. [ \t\n\r\f\v]
Vs. [:space:]
).
Dzięki temu osiągniesz to, o co prosisz, ale nie sądzę, że tego naprawdę chcesz. Umieszczam .*
przed regexem, aby zjeść wszystko przed dopasowaniem, ale jest to chciwa operacja, więc pasuje to tylko do przedostatniego \w
znaku w ciągu.
Pamiętaj, że musisz uciec przed parens i +
.
sed 's/.*\(\w\).\+/\1/' myfile.txt
sed
rereferencjami, aby to zrobić?