Jak znaleźć pozycję postaci za pomocą grep?


11

Muszę zidentyfikować pozycję znaku w ciągu za pomocą polecenia grep.

Przykład: ciąg to RAMSITALSKHMAN|1223333.

grep -n '[^a-zA-Z0-9\$\~\%\#\^]'

Jak znaleźć pozycję |w danym ciągu?


to musi być z grep?
Braiam

Odpowiedzi:


29

Możesz użyć, -baby uzyskać przesunięcie bajtu, które jest takie samo jak pozycja dla prostego tekstu (ale nie dla UTF-8 lub podobnego).

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|

Powyżej używam -aprzełącznika, aby powiedzieć grepowi, aby używał danych wejściowych jako tekstu; konieczne podczas pracy na plikach binarnych, a -oprzełącznik wyświetla tylko pasujące znaki.

Jeśli chcesz tylko pozycję, możesz użyć grep, aby wyodrębnić tylko pozycję:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14

Jeśli otrzymasz dziwny wynik, sprawdź, czy grep ma włączone kolory. Możesz wyłączyć kolory, przechodząc --colors=neverdo grep lub poprzedzając polecenie grep znakiem \(który wyłączy wszelkie aliasy), np .:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14

W przypadku ciągu, który zwraca wiele dopasowań, przeciągnij, head -n1aby uzyskać pierwsze dopasowanie.

Zauważ, że używam obu z powyższych, i zauważ, że ten ostatni nie będzie działał, jeśli grep jest „aliasowany” przez plik wykonywalny (skrypt lub w inny sposób), tylko przy użyciu aliasów.


3
Teraz szukaj 2;)
Izkata

Dzięki @Izkata, masz rację. Trochę zaktualizowałem swój post i dodałem brakujący kapelusz ^:)
runejuhl,

1
Z jakiej wersji grep korzystałeś? Dostaję 0:|jako wynik - ponieważ 0 to bajtowa pozycja początku wiersza, w którym się |znajduje.
Alex

@Alex GNU grep z odcinka wpisy: grep (GNU grep) 2.27. Być może używasz OS X?
runejuhl

11

Próbować:

printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'

wynik:

15:|

To da ci pozycję z indeksem opartym na 1.


Nie działa :(
user82782,

1
@ user82782: Jakie polecenie wykonałeś? Skąd wiesz, że to nie zadziałało?
cuonglm

printf '%s\n' '|' | grep -o . | grep -n '|'wydruki 1niezgodne z 0oczekiwaniami.
l0b0

1
@ l0b0: OP nie mówi, że chce bazy 0 lub 1.
indeksu

Mam na myśli to, czego oczekiwałby programista.
l0b0

8

Jeśli używasz powłoki , możesz korzystać z czysto wbudowanych operacji bez potrzeby odradzania procesów zewnętrznych, takich jak lub :

$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$ 

Wykorzystuje to rozszerzenie parametrów, aby usunąć wszystkie wystąpienia |następujących po dowolnym ciągu i zapisać je w zmiennej tymczasowej. W takim przypadku wystarczy zmierzyć długość zmiennej tymczasowej, aby uzyskać indeks |.

Zauważ, że ifsprawdza, czy |w ogóle istnieje w oryginalnym ciągu. Jeśli tak nie jest, zmienna tymczasowa będzie taka sama jak pierwotna.

Zauważ też, że zapewnia to indeks zerowy, |który jest ogólnie przydatny podczas indeksowania ciągów bash. Jeśli jednak potrzebujesz indeksu opartego na jednym, możesz to zrobić:

$ echo $((${#tmp}+1))
15
$ 

1
prawdopodobnie najlepsza odpowiedź, ta składnia jest piękna i tak szybka i łatwa w użyciu, gdy zrozumiesz jej znaczenie, niech żyje do samego rdzenia
vdegenne

4

Możesz użyć indexfunkcji awk, aby zwrócić pozycję w znakach, w których występuje dopasowanie:

echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15

Jeśli nie masz nic przeciwko użyciu funkcji Perla index, obsługuje to zgłaszanie zera, jednego lub więcej wystąpień znaku:

echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'

Tylko w celu zapewnienia czytelności potok został podzielony na dwie linie.

Dopóki znak docelowy zostanie znaleziony, indexzwraca wartość dodatnią w oparciu o zero (0). Stąd ciąg „abc | xyz | 123456 | zzz |” po przeanalizowaniu zwraca pozycje 0, 4, 8, 15 i 19.


w tym celu awk jest bardziej użyteczny / łatwy niż grep.
Archemar

To tylko wydrukuje pierwszą pozycję, nie będzie działać z ciągiem jakRAMSITALSKHMAN|1|223333
cuonglm

3

Możemy to również zrobić za pomocą „dopasowania wyrażenia” lub „indeksu wyrażenia”

wyrażenie dopasowuje $ string $ substring, gdzie $ substring jest RE.

echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`

A powyżej da ci pozycję, ponieważ zwraca dopasowaną długość podłańcucha.

Ale aby być bardziej szczegółowym w wyszukiwaniu indeksu:

mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`

Nie mam wystarczającej reputacji, aby komentować gdzie indziej. Osobiście podobała mi się odpowiedź udzielona przez @Gnouc. Jednak po co używać awk i
komplikować

@kingsdeb to tylko sugestia.
Avinash Raj

@kingsdeb: Ponieważ (1) awkrozwiązania można w trywialny sposób modyfikować w celu zgłaszania tych informacji w każdym wierszu pliku (wszystko, co musisz zrobić, to usunąć ENDodpowiedź JRFergusona, która nigdy nie była tak naprawdę konieczna, a Avinash Raj już to robi) ; mając na uwadze, że aby to zrobić za pomocą exprrozwiązania, należy dodać wyraźną pętlę (a odpowiedź Gnouca nie jest łatwa do dostosowania, aby to zrobić w ogóle, co widzę), oraz (2) awkrozwiązania można dostosować do zgłaszania wszystkich dopasowuje się w każdej linii nieco łatwiej niż exprrozwiązanie (w rzeczywistości Avinash Raj już to robi).
G-Man mówi „Reinstate Monica”

Dlaczego miałbyś echo `...`tu skorzystać ?
Stéphane Chazelas

Ma to tylko pokazać wynik tutaj
bluefoggy

2

Kolejne polecenie awk ,

$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15

Ustawiając separator pól jako ciąg zerowy, awk zamienia pojedynczy znak w rekordzie jako osobne pola.


2

niektóre alternatywy obejmują:

podobny do odpowiedzi Gnouca, ale z powłoką:

echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n | 
sh

sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'

z sedi dcprawdopodobnie obejmujący wiele linii:

echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc

15

z $IFS...

IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))

To będzie również powiedzieć, jak wiele istnieje jak ...

echo $(($#-1))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.