Como fazer uma correspondência de texto no bash

1

Estou tentando encontrar uma maneira legal de verificar algum texto para definir uma variável. Por exemplo, para executar a lógica: 'se a string de versão for 1.x, então defina um flag'. Uma maneira de fazer isso é:

versionFlag="0"
if grep -q "^1.*" versionfile; then
  versionFlag="1"
fi

que é um pouco detalhado. Se eu quiser ativar várias possibilidades, é mais fácil:

case 'grep "^1.*" versionfile' in
  1.*)
    echo "version 1"
    ;;
...
esac

Mas existe uma forma de apenas uma linha de apenas definir um sinalizador como verdadeiro ou falso se algum texto corresponder a um regexp ou a um caractere curinga?

    
por the_mandrill 15.02.2010 / 14:00

4 respostas

3
versionFlag='grep "^1.*" /tmp/test | wc -l'

versionFlag é então definido como 0. Todos os dados nas correspondências de teste, versionFlag é definido para o número de linhas que correspondem, então

if [ $versionFlag == 0 ] ; then
  echo false
else
  echo true 
fi

edit: isso pode ser feito ainda mais simplesmente

versionFlag=$(grep "^1.*" /tmp/test -c)

que retornará uma contagem de instâncias no arquivo

    
por 15.02.2010 / 14:09
2

Você pode fazer algo parecido com isto no bash 3.x (versões mais antigas não suportam correspondência de regex)

version='cat versionfile'
[[ $version =~ "^1.*" ]] && versionFlag=1
    
por 15.02.2010 / 14:12
0

Não há um operador ternário (por exemplo,? :) no bash, então você está preso ao seu if e, em seguida, construir várias linhas. Você poderia usar um idioma diferente que tenha um operador ternário (PERL, por exemplo).

Lembre-se, muita gente desestimula o uso de operadores ternários, já que eles não são tão fáceis de ler em código - em outras palavras, seus comentários acabam sendo mais longos do que as várias linhas de código teriam sido.

Eu duvido que haja um benefício de desempenho de qualquer um dos métodos.

    
por 15.02.2010 / 14:16
0

Na verdade, essa construção:

[[ $version =~ ^1\.+ ]] && versionFlag=1

é facilmente estendido para suportar o caso "sem correspondência"; basta fazer isso:

[[ $version =~ ^1\.+ ]] && versionFlag=1 || versionFlag=0

Incidentalmente, observe a mudança de '*' para '+' na regex. Usando a estrela, a regex ainda corresponderá incorretamente em um valor de versão de "10". (O modificador '*' significa "corresponde a zero ou mais ocorrências", isto é, você ainda não precisa ter um ponto decimal; o modificador '+' significa "corresponde a uma ou mais ocorrências"). , significa que "1" (ou seja, um valor sem um decimal) não corresponderá a ; isso pode ou não ser um problema para seu aplicativo.

Existe também uma maneira de fazer isso sem usar o operador regex-match, caso você não o tenha; tente isso:

[[ ${version#1.} != ${version} ]] && versionFlag=1 || versionFlag=0

Esta é apenas uma correspondência de padrões, não uma regex, então se você realmente precisa da funcionalidade regex, ela não funcionará, mas para coisas simples, é ótimo. (Se você não estiver familiarizado com essa forma de expansão de parâmetro, a construção "$ {version # 1.}" Expande para o valor de "version", mas com o padrão post - '#' removido do início do valor se estava originalmente lá Exemplo: Se "version" tem um valor de "1.03", o resultado de "$ {version # 1.}" é "03". Como isso difere do valor original, o "!=" teste é bem sucedido.)

    
por 05.08.2010 / 17:26