Como nego um teste com expressões regulares em um script bash?


173

Usando o GNU bash (versão 4.0.35 (1) -release (x86_64-suse-linux-gnu)), eu gostaria de negar um teste com expressões regulares. Por exemplo, gostaria de adicionar condicionalmente um caminho à variável PATH, se o caminho ainda não estiver lá, como em:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Tenho certeza de que existem milhões de maneiras de fazer isso, mas o que eu gostaria de saber é se o condicional pode ser negado de alguma forma, como em (o incorreto):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH

Respostas:


193

Você acertou, basta colocar um espaço entre o !e [[assim por dianteif ! [[


14
Oye vey! Apenas quando eu evito com segurança a loucura intergaláctica do perl por caracteres especiais, me vejo perdido no espaço do bash (posicionamento)! (Sinto medo apertando meu intestino como uma píton.) Obrigado!
— David Rogers

126

Você também pode colocar o ponto de exclamação dentro dos colchetes:

if [[ ! $PATH =~ $temp ]]

mas você deve ancorar seu padrão para reduzir falsos positivos:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

que procura uma correspondência no início ou no final com dois pontos antes ou depois dela (ou de ambos). Eu recomendo o uso de nomes de variáveis ​​em minúsculas ou mistas como hábito para reduzir a chance de colisões de nomes com variáveis ​​de shell.


Ah, obrigado pelo lembrete sobre ancoragem. A idéia de usar nomes de variáveis ​​minúsculas ou mistas é confusa para um iniciante do bash, pois o conselho que vi até agora é usar letras maiúsculas. Entendo o que você está dizendo, mas não vi exemplos suficientes de scripts do bash para me sentir confortável em desviar do (meu entendimento) do livro de receitas.
— David Rogers

4
@anyoneis confia em nós neste. O uso de variáveis ​​maiúsculas definidas pelo usuário deve ser evitado. Todas as variáveis ​​no bash são expandidas e, $portanto, não há razão para colocá-las em maiúsculas para destacá-las.
— SiegeX 01/01

Acho if [[ ! $foo =~ bar ]]mais seguro do que if ! [[ $foo =~ bar ]], porque facilita a introdução de mais condições para oif
— CTodea 27/17/17

19

a maneira mais segura é colocar o! para a negação de regex dentro da [[ ]]seguinte maneira:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

caso contrário, poderá falhar em certos sistemas.


9

Sim, você pode negar o teste, como o SiegeX já apontou.

No entanto, você não deve usar expressões regulares para isso - pode falhar se o seu caminho contiver caracteres especiais. Tente isso:

[[ ":$PATH:" != *":$1:"* ]]

(Fonte)


1
Outro motivo para usar este formulário é que ele não coincide acidentalmente com as substrings (por exemplo, falha ao adicionar "/ bin" ao caminho porque "/ usr / bin" já está lá).
— Gordon Davisson

Demorei um pouco para entender como os dois pontos à esquerda me deram a ancoragem que eu queria. vale a pena lembrar a idéia de reduzir o padrão adicionando material à sequência a ser pesquisada. Não entendo por que caracteres especiais no caminho interromperiam a solução regex, mas não a solução do padrão bash. Você pode me dar um exemplo?
— David Rogers

Eu não acho que isso funcione de maneira confiável em todos os casos. Correspondência de regex em IMHO superiores
— Felipe Alvarez

5

Eu gosto de simplificar o código sem usar operadores condicionais nesses casos:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.