Escapando caracteres para a condição grep exata em um script Bash

0

Eu tenho um script básico para encontrar pacotes instalados específicos no Linux. Se não for encontrado - > imprima o pacote.

Eu usei grep -w , mas não funcionou corretamente com o caractere - .

Por exemplo,

dpkg -l | grep -w "rpm"

Também encontrará rpm-common .

Eu encontrei uma solução para isso usando o regex. O problema é que não funciona em um script Bash.

Solução:

dpkg -l | grep -E '(^|\s)string($|\s)'

Condição:

if [ 'dpkg -l | grep -E '(^|\s)$i($|\s)' | wc -l' = 0 ]; then echo$i; fi

$i refere-se a um valor de matriz, como arr[index]=$i .

Quais caracteres de escape eu preciso usar para que a condição funcione?

    
por igor 16.11.2017 / 15:36

2 respostas

1

Existem dois problemas aqui: como @AFH apontou, \s é uma abreviação de Perl, não faz parte da sintaxe POSIX padrão. A maneira padrão de representar isso é com a classe de caractere [[:space:]] . O segundo problema é que as referências de variáveis não são expandidas entre aspas simples; você precisa usar aspas duplas (e escapar do $ que é parte do regex).

Além disso, algumas das recomendações estilísticas: $( ) é geralmente preferido em relação aos backticks para a substituição de comandos (é mais fácil de ler e não tem algumas estranhezas de sintaxe de escape que os backticks têm). Mas neste caso, você pode pular a expansão de comando; em vez de usar wc -l e comparar com zero para ver se houve alguma correspondência, use apenas o status de saída de grep como seu teste (e a opção -q para evitar que ela imprima a correspondência). Além disso, certifique-se de fazer aspas duplas nas referências de variáveis (por exemplo, no comando echo ).

Aqui está minha reescrita recomendada:

if dpkg -l | grep -Eq "(^|[[:space:]])$i(\$|[[:space:]])"; then echo "$i"; fi

EDIT: como igor apontou em um comentário, isso não funcionará com nomes de pacotes que contenham metacaracteres de regex (como g ++ - 5). É possível pré-processar o nome do pacote para escapar dos metacaracteres, mas é bastante confuso. Mas há uma maneira mais simples: se você estiver usando o bash (e não algum outro shell), você pode usar o recurso de regex nativo do bash para fazer a correspondência diretamente:

if [[ "$(dpkg -l)" =~ (^|[[:space:]])"$i"(\$|[[:space:]]) ]]; then echo "$i"; fi

O motivo pelo qual isso funciona é que o $i no meio do padrão está entre aspas duplas, o que diz ao bash para combiná-lo como uma cadeia literal (isto é, ignorar quaisquer metacaracteres de expressão regular nele).

    
por 16.11.2017 / 18:55
1

Expressões regulares estendidas não suportam \s , mas as REs de Perl, portanto, tente usar -P em vez de -E :

dpkg -l | grep -P '(^|\s)rpm($|\s)'

Consulte esta referência para obter mais informações.

O manual grep diz que -P é experimental, mas funciona para mim no Ubuntu 16.04.

    
por 16.11.2017 / 16:10