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?
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?
Odpowiedzi:
Możesz użyć, -b
aby 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 -a
przełącznika, aby powiedzieć grepowi, aby używał danych wejściowych jako tekstu; konieczne podczas pracy na plikach binarnych, a -o
przełą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=never
do 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 -n1
aby 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.
2
;)
^
:)
0:|
jako wynik - ponieważ 0 to bajtowa pozycja początku wiersza, w którym się |
znajduje.
grep (GNU grep) 2.27
. Być może używasz OS X?
Próbować:
printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'
wynik:
15:|
To da ci pozycję z indeksem opartym na 1.
printf '%s\n' '|' | grep -o . | grep -n '|'
wydruki 1
niezgodne z 0
oczekiwaniami.
Jeśli używasz powłoki bash , możesz korzystać z czysto wbudowanych operacji bez potrzeby odradzania procesów zewnętrznych, takich jak grep lub awk :
$ 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 if
sprawdza, 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
$
Możesz użyć index
funkcji 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, index
zwraca 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.
RAMSITALSKHMAN|1|223333
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" '|'`
awk
rozwią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ąć END
odpowiedź 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ą expr
rozwią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) awk
rozwiązania można dostosować do zgłaszania wszystkich dopasowuje się w każdej linii nieco łatwiej niż expr
rozwiązanie (w rzeczywistości Avinash Raj już to robi).
echo `...`
tu skorzystać ?
$ 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.
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 sed
i dc
prawdopodobnie 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))