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).