Como encontrar uma posição de um personagem usando grep?

10

Eu preciso identificar a posição de um caractere na string usando o comando grep.

Exemplo, a sequência é RAMSITALSKHMAN|1223333.

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

Como encontro a posição de |na string especificada?

user82782
fonte
tem que ser com grep?
Braiam

Respostas:

28

Você pode usar -bpara obter o deslocamento de bytes, que é o mesmo da posição para texto simples (mas não para UTF-8 ou similar).

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

No exemplo acima, eu uso o -aswitch para dizer ao grep para usar a entrada como texto; necessário ao operar em arquivos binários, e a -oopção para gerar apenas os caracteres correspondentes.

Se você deseja apenas a posição, pode usar grep para extrair apenas a posição:

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

Se você obtiver uma saída estranha, verifique se o grep tem as cores ativadas. Você pode desativar as cores passando --colors=neverpara grep ou prefixando o comando grep com um \(que desativará qualquer apelido), por exemplo:

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

Para uma sequência que retorna várias correspondências, passe head -n1para obter a primeira correspondência.

Observe que eu uso os dois itens acima e observe que este último não funcionará se o grep for "alias" através de um executável (script ou outro), apenas ao usar aliases.

runejuhl
fonte
3
Agora pesquise 2;)
Izkata 2/14
Obrigado @Izkata, você está certo. Eu atualizei meu post um pouco e acrescentou o chapéu ausente ^:)
runejuhl
1
Qual versão do grep você usou? Eu recebo 0:|como output-- porque 0 é a posição de byte do início da linha onde |é encontrado.
25417 Alex
@Alex GNU grep do trecho Debian: grep (GNU grep) 2.27. Você talvez esteja usando o OS X?
Runejuhl
11

Experimentar:

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

resultado:

15:|

Isso fornecerá a posição com o índice baseado em 1.

cuonglm
fonte
Não está funcionando :(
user82782
1
@ user82782: Que comando você executou? Como você sabe que não funcionou?
cuonglm
printf '%s\n' '|' | grep -o . | grep -n '|'imprime 1, não 0conforme o esperado.
l0b0 02/09
1
@ l0b0: O OP não dizer que ele queria índice de base 0 ou 1.
cuonglm
Eu apenas quero dizer o que um desenvolvedor de software esperaria.
L0b0 02/09
8

Se você estiver usando o shell , poderá usar operações puramente internas sem a necessidade de gerar processos externos, como ou :

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

Isso usa uma expansão de parâmetro para remover todas as ocorrências de |segue por qualquer sequência e salvar em uma variável temporária. É apenas uma questão de medir o comprimento da variável temporária para obter o índice de |.

Observe que ifestá verificando se |existe alguma na string original. Caso contrário, a variável temporária será igual ao original.

Observe também que isso fornece o índice baseado em zero, o |que geralmente é útil na indexação de strings do bash. No entanto, se você precisar do índice baseado em um, poderá fazer o seguinte:

$ echo $((${#tmp}+1))
15
$ 
Trauma Digital
fonte
1
provavelmente a melhor resposta, esta sintaxe é bonito e tão rápido e fácil de usar quando você compreender o seu significado, viva para o núcleo
vdegenne
4

Você pode usar a indexfunção do awk para retornar a posição nos caracteres em que a correspondência ocorre:

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

Se você não se importa em usar a indexfunção Perl , isso lida com o relato de zero, uma ou mais ocorrências de um personagem:

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

Apenas para facilitar a leitura, o pipeline foi dividido em duas linhas.

Desde que o caractere alvo seja encontrado, indexretorna um valor positivo com base em zero (0). Portanto, a cadeia "abc | xyz | 123456 | zzz |" quando analisado retorna as posições 0, 4, 8, 15 e 19.

JRFerguson
fonte
para esse uso, o awk é mais útil / fácil do que o grep.
Archemar 02/09
Isso só imprimir a primeira posição, não vai funcionar com a corda comoRAMSITALSKHMAN|1|223333
cuonglm
3

Também podemos fazer isso usando "expr match" ou "expr index"

expr corresponde a $ string $ substring em que $ substring é um RE.

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

E acima, você fornecerá a posição, pois retorna o comprimento da substring correspondente.

Mas, para ser mais específico na pesquisa de índice:

mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`
bluefoggy
fonte
Não tenho reputação suficiente para comentar em nenhum outro lugar. Pessoalmente, gostei da resposta dada por @Gnouc. No entanto por que usar awk e torná-lo complexo quando podemos fazer coisas simples usando 'expr'
bluefoggy
@kingsdeb é apenas uma sugestão.
Avinash Raj
@kingsdeb: Porque (1) as awksoluções podem ser modificadas trivialmente para relatar essas informações em todas as linhas de um arquivo (tudo o que você precisa fazer é remover o END, o que nunca foi realmente necessário, da resposta de JRFerguson, e o Avinash Raj já o faz) ; considerando que, para fazer isso com a exprsolução, você precisará adicionar um loop explícito (e a resposta do Gnouc não é facilmente adaptável a isso, pelo que vejo) e (2) as awksoluções podem ser adaptadas para relatar todas as corresponde em cada linha um pouco mais facilmente do que a exprsolução (na verdade, a Avinash Raj já faz isso também).
G-Man diz 'Restabelecer Monica
Por que você usaria echo `...`aqui?
Stéphane Chazelas
Este é apenas para mostrar a saída aqui
bluefoggy
2

Outro comando awk ,

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

Ao definir o separador de campos como sequência nula, o awk transforma caracteres individuais no registro como campos separados.

Avinash Raj
fonte
2

algumas alternativas incluem:

semelhante à resposta de Gnouc, mas com a casca:

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

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

com sede dcpossivelmente abrangendo várias linhas:

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

15

com $IFS...

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

Isso também irá dizer-lhe como muitos há como ...

echo $(($#-1))
mikeserv
fonte