bash regex não reconhece todos os grupos

1

Eu preciso capturar grupos de uma expressão regular. Mas parece que não consigo entender o conceito da variável bash BASH_REMATCH , pois não consigo obter alguns grupos. Aqui está o meu código:

# I want to get the values around the first '=' if it exists
inp="short =  some word  long = span desc=sth to ' be ' described value=45"
regex="\s*(\w*)\s*=\s*(.*)"

if [[ $inp =~ $regex ]]; then 
  echo; 
  echo -e "input: \"$inp\""; 
  echo -e "regex: \"$regex\"";   
  echo "matching groups: ${#BASH_REMATCH[*]}"; 
  for i in $(seq 0 $(( ${#BASH_REMATCH[*]}-1 ))); do 
    echo -e "$i: \"${BASH_REMATCH[$i]}\""; 
  done; 
fi

input: "short =  some word  long = span desc=sth to ' be ' described value=45"
regex: "\s*(\w*)\s*=\s*(.*)"
matching groups: 3
0: "=  some word  long = span desc=sth to ' be ' described value=45"
1: ""
2: "  some word  long = span desc=sth to ' be ' described value=45"

Espero que o primeiro grupo seja "curto". Por que não é reconhecido? Se eu testar minha expressão regular em regex101.com, ela me informará o grupo 1 "curto". Aqui está o link: link

Editar 1

O primeiro grupo é reconhecido usando sed (usei o mesmo regex, exceto que escapei do parêntese de agrupamento):

$ sed 's/\s*\(\w*\)\s*=\s*\(.*\)/\n/' <<< $inp
short
some word  long = span desc=sth to ' be ' described value=45

EDIT 2

Como sugerido, tentei colocar âncoras no regex e nenhum resultado é reconhecido desta vez:

regex="^\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)$"
regex="^\s*(\w+)\s*=\s*(.*)$"

Nenhum desses regex funciona, não tenho resultado algum.

Eu verifiquei os valores hexadecimais da string:

$ od -vAn -tx1c <<<"$inp"
           73  68  6f  72  74  20  3d  20  20  73  6f  6d  65  20  77  6f
           s   h   o   r   t       =           s   o   m   e       w   o
           72  64  20  20  6c  6f  6e  67  20  3d  20  73  70  61  6e  20
           r   d           l   o   n   g       =       s   p   a   n    
           64  65  73  63  3d  73  74  68  20  74  6f  20  27  20  62  65
           d   e   s   c   =   s   t   h       t   o       '       b   e
           20  27  20  64  65  73  63  72  69  62  65  64  20  76  61  6c
               '       d   e   s   c   r   i   b   e   d       v   a   l
           75  65  3d  34  35  0a                                        
           u   e   =   4   5  \n 

Não parece ser um personagem esquisito.

Para informações, estou usando o bash v 4.4.0, no mac:

$ bash --version
GNU bash, version 4.4.0(1)-release (x86_64-apple-darwin15.6.0)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

EDIT 3

Alguns novos. Eu tentei em uma máquina linux, usando bash v. 4.1.2, inferior então:

$ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Todos esses três trabalhos de regex:

regex="\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)"
regex="^\s*(\w*)\s*=\s*(.*)$"
regex="^\s*(\w+)\s*=\s*(.*)$"

Eu obtenho o resultado:

input: "short =  some word  long = span desc=sth to ' be ' described value=45"
regex: "^\s*(\w*)\s*=\s*(.*)"
matching groups: 3
0: "short =  some word  long = span desc=sth to ' be ' described value=45"
1: "short"
2: "some word  long = span desc=sth to ' be ' described value=45"

Este é exatamente o resultado que eu espero. Mas por que não funciona corretamente no meu mac? A versão de bash é mais recente. Eu gostaria de uma solução que funcione com todas as versões recentes do bash.

    
por kaligne 05.01.2017 / 11:01

1 resposta

2

O regex de Bash não está ancorado. Isso significa que eles podem corresponder em qualquer lugar da string. Depende do seu motor regex. Aqui, a partida começa no sinal de igual, como mostrado por BASH_REMATCH[0] .

Solução: adicione um ^ no início da string regex .

[update] Como dito acima, bash usa seu mecanismo de regex ( man 3 regex ) que pode diferir de uma plataforma para outra. Se você tiver problemas com sua regex, evite \letter atalhos e use seu equivalente Posix.

Por exemplo, em vez de regex="^\s*(\w*)\s*=\s*(.*)"
use regex="^[[:space:]]*([_[:alnum:]]*)[[:space:]]*=[[:space:]]*(.*)"

    
por 05.01.2017 / 12:02