Як знайти позицію персонажа за допомогою grep?


11

Мені потрібно визначити позицію символу в рядку за допомогою команди grep.

Наприклад, рядок є RAMSITALSKHMAN|1223333.

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

Як знайти позицію |в даному рядку?


це має бути з грепом?
Брайам

Відповіді:


29

Ви можете використовувати -bдля зміщення байту, що є тим самим, що і положення для простого тексту (але не для UTF-8 або подібного).

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

У вищесказаному я використовую -aперемикач, щоб сказати grep використовувати вхід як текст; необхідний під час роботи над бінарними файлами, і -oперемикач виводить лише відповідні символи.

Якщо ви хочете лише позицію, ви можете використовувати grep, щоб витягнути лише позицію:

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

Якщо ви отримуєте дивний вихід, перевірте, чи у грепі не включені кольори. Ви можете відключити кольори, перейшовши --colors=neverна grep або встановивши префікс команди grep за допомогою \(що вимкне будь-які псевдоніми), наприклад:

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

Для рядка, який повертає декілька збігів, перейдіть, head -n1щоб отримати перший збіг.

Зауважте, що я використовую і те, і інше вище, і зауважте, що останній не буде працювати, якщо grep "псевдонім" через виконуваний файл (сценарій чи іншим способом), лише при використанні псевдонімів.


3
Зараз шукайте 2;)
Ізката

Дякую @Izkata, ти маєш рацію. Я трохи оновив свій пост і додав пропущений капелюх ^:)
runejuhl

1
Яку версію grep ви використовували? Я отримую 0:|як вихід-- тому що 0 - це позиція байту початку рядка, де |його знайдено.
Олексій

@ Алекс GNU grep від Debian stretch : grep (GNU grep) 2.27. Можливо, ви використовуєте OS X?
runejuhl

11

Спробуйте:

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

вихід:

15:|

Це дасть вам позицію з індексом-1.


Його не працює :(
user82782

1
@ user82782: Яку команду ви виконали? Звідки ви знаєте, що це не спрацювало?
cuonglm

printf '%s\n' '|' | grep -o . | grep -n '|'відбитки 1, не так, 0як очікувалося.
l0b0

1
@ l0b0: ОП не каже, що він хотів базу індексу 0 або 1.
cuonglm

Я маю на увазі, що очікував розробник програмного забезпечення.
l0b0

8

Якщо ви використовуєте shell, ви можете використовувати суто вбудовані операції без необхідності нерестувати зовнішні процеси, такі як або :

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

При цьому використовується розширення параметрів, щоб видалити всі входження, що |випливають далі, будь-яким рядком і зберегти його у тимчасовій змінній. Тоді просто питання вимірювання довжини тимчасової змінної отримати індекс |.

Зверніть увагу, що ifце перевірка, чи |існує взагалі в початковому рядку. Якщо це не так, тимчасова змінна буде такою ж, як і первісна.

Зверніть увагу також, що це дає нульовий індекс, |який, як правило, корисний при індексації рядків bash. Однак якщо вам потрібен єдиний індекс, ви можете зробити це:

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

1
Мабуть, найкраща відповідь, цей синтаксис прекрасний, настільки швидкий і простий у використанні, коли ви розумієте його значення,
хай

4

Ви можете використовувати indexфункцію awk для повернення позиції в символах, де відбувається збіг:

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

Якщо ви не заперечуєте проти використання функції Perl index, це обробляє повідомлення про нуль, одне або кілька входів символу:

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

Щодо читання, трубопровід був розділений на дві лінії.

Поки знайдений цільовий символ, indexповертає додатне значення на основі нуля (0). Отже, рядок "abc | xyz | 123456 | zzz |" при розборі повертає позиції 0, 4, 8, 15 і 19.


для цього використання awk корисніше / легше ніж grep.
Архемар

Це тільки друк першої позиції, не працюватиме на зразок рядкаRAMSITALSKHMAN|1|223333
cuonglm

3

Ми також можемо це зробити за допомогою "expr match" або "expr index"

expr відповідає $ string $ substring, де $ substring - це RE.

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

А вище надасть вам позицію, оскільки вона повертає довжину зібраної підрядки.

Але щоб бути більш конкретним для пошукового індексу:

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

У мене недостатньо репутації для коментарів деінде. Мені особисто сподобалась відповідь, надана @Gnouc. Однак навіщо використовувати awk і ускладнювати його, коли ми можемо робити прості речі, використовуючи 'expr'
bluefoggy

@kingsdeb це лише пропозиція.
Avinash Raj

@kingsdeb: Оскільки (1) awkрішення можна тривіально модифікувати, щоб повідомляти про цю інформацію в кожному рядку файлу (все, що вам потрібно зробити, - це видалити END, що ніколи насправді не було потрібно, з відповіді JRFerguson, і Avinash Raj's це вже робить) ; оскільки для цього з exprрішенням вам потрібно буде додати явний цикл (і відповідь Gnouc не легко адаптується, щоб це зробити взагалі, що я бачу), і (2) awkрішення можуть бути адаптовані так, щоб повідомляти про всі Збігається в кожному рядку дещо простіше, ніж exprрішення (насправді, це теж робить Авінаш Радж).
G-Man каже: "Відновіть Моніку"

Для чого ти echo `...`тут використовуєшся ?
Stéphane Chazelas

Це просто показати результат тут
bluefoggy

2

Ще одна команда awk ,

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

Встановивши роздільник поля як нульовий рядок, awk перетворює окремий символ у записі як окремі поля.


2

деякі альтернативи включають:

подібний до відповіді Гнука, але з оболонкою:

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

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

з sedі, dcможливо, охоплюючи кілька рядків:

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

15

з $IFS...

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

Це буде також сказати вам , як багато є , як ...

echo $(($#-1))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.