Como usar uma repetição com um escape hexadecimal com um operador regex bash

1

Eu tenho lutado por dias para tentar fazer com que algo aparentemente simples funcione.

(LC_ALL=POSIX; regex="src\.[\x20-\x7E]+\.system"; file="src.dirtree.system";
 if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)

O desejo é combinar src. *. system onde o * pode ser qualquer coisa no intervalo de caracteres \x21-\x7E . Se eu quisesse \x20-\x7E , então [ -~]+ funcionaria, mas como conseguir esse intervalo funcionar ou qualquer intervalo de escape hexadecimal arbitrário com repetições *, + or {x,y} ?

A versão do Bash é 4.3.11(1)-release e não, não posso alterá-la.

    
por Supernovah 05.04.2018 / 09:36

1 resposta

1

Uma olhada na documentação do Bash refere-se a man 3 regex para detalhes:

An additional binary operator, ‘=~’, is available, with the same precedence as ‘==’ and ‘!=’. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex 3)).

man 3 regex no Linux indica que são regexes POSIX confirmados pela descrição de o sinalizador de configuração necessário para permitir isso:

--enable-cond-regexp
Include support for matching POSIX regular expressions using the ‘=~’ binary operator in the [[ conditional command. (see Conditional Constructs).

E man 7 regex , que descreve a sintaxe, diz:

With the exception of these and some combinations using '[' (see next paragraphs), all other special characters, including '\', lose their special significance within a bracket expression.

E não faz menção aos intervalos de bytes hexadecimais. Então, eu diria que isso não é diretamente possível.

Você pode abusar do recurso de citação ANSI C para substituir os bytes reais das suas versões hexadecimais:

$ (LC_ALL=POSIX; regex="src\.["$'\x21-\x7E'"]+\.system"; file='src.dir!ree.system';  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
yes
$ (LC_ALL=POSIX; regex="src\.["$'\x21-\x7E'"]+\.system"; file='src.dir ree.system';  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
no
$ (LC_ALL=POSIX; regex="src\.["$'\x21-\x7E'"]+\.system"; file="src.dirtree.system";  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
yes

Observe como regex é a concatenação de três strings: "src\." , $'\x21-\x7E' (que é expandida para os bytes correspondentes) e "]+\.system" .

Embora, é claro, para este caso você poderia ter usado juste !-~ , devidamente citado:

$ (LC_ALL=POSIX; regex='src\.[!-~]+\.system'; file='src.dirtree.system';  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
yes
$ (LC_ALL=POSIX; regex='src\.[!-~]+\.system'; file='src.dir!ree.system';  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
yes
$ (LC_ALL=POSIX; regex='src\.[!-~]+\.system'; file='src.dir ree.system';  if [[ $file =~ $regex ]]; then echo "yes"; else echo "no"; fi;)
no

Ou [[:graph:]] , que acho que deve ser o mesmo intervalo para caracteres ASCII.

    
por 05.04.2018 / 11:47