Combinando operadores relacionais com grep -q na instrução shell IF?

0

Não consigo encontrar uma resposta para isso - peço desculpas se for uma cópia.

Estou usando /bin/sh no BSD ( não bash!) e estou tentando descobrir a sintaxe para a seguinte instrução IF.

Eu tenho duas cláusulas componentes. Escrito como declarações separadas, é assim:

if [ "$a" == "y" -o "$a" == "Y" ]; then
    if printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
        # both conditions met: do stuff
    fi
fi

Portanto, posso usar aninhado if como solução alternativa.

Mas qual a sintaxe de que preciso, para combiná-las perfeitamente em uma única instrução "if"?

OBSERVAÇÃO: Se esse shell permitir comparações diretas de correspondência de expressão regular ( [ "$a" =~ REGEX" ] ou similar) em vez de exigir grep -q , seria útil saber, mas ainda gostaria de saber como combinar corretamente essas cláusulas como estão, porque algum dia eu certamente terei uma situação onde eu estou combinando o conteúdo do arquivo e a segunda instrução é algo como ls -l "$b" | grep -qE 'SOME_REGEX' , então uma comparação de regex inline não funcionaria ...:)

    
por Stilez 01.08.2018 / 15:10

3 respostas

3

Pessoalmente, acho que não há problema em ter uma instrução if aninhada aqui, embora eu usasse uma sintaxe ligeiramente modernizada:

if [ "$a" = "y" ] || [ "$a" = "Y" ]; then
    if printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
        # both conditions met: do stuff
    fi
fi

(observe que == é um bash -ism)

Para combiná-los (torna IMHO menos legível):

if [ "$a" = "y" ] || [ "$a" = "Y" ] && printf '%s' "$b" | grep -qE 'SOME_REGEX'; then
    # both conditions met: do stuff
fi

Para expressões regulares básicas , você pode usar expr (consulte comentário por Stéphane Chazelas abaixo embora ):

if [ "$a" = "y" ] || [ "$a" = "Y" ] && expr "$b" : 'SOME_REGEX' >/dev/null; then
    # both conditions met: do stuff
fi

O shell /bin/sh geralmente não tem [[ ... =~ ... ]] para corresponder à expressão regular estendida.

Com relação à sua nota no final: expressões regulares são para correspondência entre linhas simples de texto . Se você tratar nomes de arquivos como texto, desqualifica automaticamente qualquer nome de arquivo que não seja uma única linha de texto, como nomes de arquivos contendo novas linhas. Se você precisar aplicar a expressão regular correspondente aos nomes de arquivos, faça isso com os nomes armazenados em uma matriz ( $@ in /bin/sh ) ou use uma implementação de find que suporte o predicado -regex .

Padrões globbing de nome de arquivo são para nomes de arquivos correspondentes.

    
por 01.08.2018 / 15:16
1

Observe que grep corresponde a cada linha da entrada, não a entrada como um todo, portanto, geralmente não é adequada para cadeias arbitrárias. Você pode usar awk para isso (cuidado com as expressões regulares estendidas semelhantes àquelas entendidas por grep -E ou bash ' [[ string =~ regexp ]] ).

regexp_match() {
  awk 'BEGIN{if (ARGV[1] !~ ARGV[2]) exit(1)}' "$@"
}

if [ "$a" = y ] || [ "$a" = Y ] && regexp_match "$b" REGEXP; then
   ...
fi

Observe que os operadores binários -a / -o [ devem ser evitados. Eles são reprovados pelo POSIX e possuem vários problemas. Por exemplo, aqui no FreeBSD:

$ a='(' /bin/sh -c '[ "$a" = y -o "$a" = Y ]'
[: closing paren expected
    
por 01.08.2018 / 15:41
0

Você pode encurtar isso fazendo $a concatenar com $b e adicionar padrão à regex

 if printf '%s%s\n' "$a" "$b" | grep -qE '^[yY]SOME_REGEX'; then

Observe que o grep é uma ferramenta de correspondência de linha, portanto, \ n no final

    
por 01.08.2018 / 16:39