bash: teste se $ WORD está no conjunto

Estou procurando uma construção em bash, para decidir se uma variável $WORD é uma das palavras definidas. Preciso de algo assim:

if "$WORD" in dog cat horse ; then echo yes else echo no fi 

O bash tem essa construção? Se não, qual seria a mais próxima?

Resposta

Esta é uma solução apenas para Bash (> = versão 3) que usa expressões regulares:

if [[ "$WORD" =~ ^(cat|dog|horse)$ ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Se sua lista de palavras for longa, você pode armazená-la em um arquivo (uma palavra por linha) e fazer o seguinte:

if [[ "$WORD" =~ $(echo ^\($(paste -sd"|" /your/file)\)$) ]]; then echo "$WORD is in the list" else echo "$WORD is not in the list" fi 

Uma advertência com a abordagem do arquivo:

  • Ele será interrompido se o arquivo tiver espaço em branco. Isso pode ser remediado por algo como:

    sed "s/[[:blank:]]//g" /your/file | paste -sd "|" /dev/stdin 

Obrigado a @terdon por me lembrar de ancorar adequadamente o padrão com ^ e $.

Comentários

  • E shopt -s nocasematch pode ajudar se você quiser que a pesquisa não faça distinção entre maiúsculas e minúsculas.
  • Observe que você deve usar [[ e ]][ e ] não são suficientes.
  • eu estava procurando para um ‘ oneliner ‘ para validar meu argumento de script e funcionou perfeitamente. obrigada! [[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
  • Se você ‘ for colocar sua lista de correspondências em um arquivo, pode também usar grep: egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK".

Resposta

case $word in dog|cat|horse) echo yes;; *) echo no;; esac 

Resposta

Que tal:

#!/usr/bin/env bash WORD="$1" for w in dog cat horse do if [ "$w" == "$WORD" ] then yes=1 break fi done; [ "$yes" == "1" ] && echo "$WORD is in the list" || echo "$WORD is not in the list" 

Então:

$ a.sh cat cat is in the list $ a.sh bob bob is not in the list 

Resposta

if (echo "$set" | fgrep -q "$WORD") 

Comentários

  • Mas cuidado, isso retornará verdadeiro se $WORD estiver vazio, corresponderá se WORD=ca ou WORD=og ou semelhante e suponho que você quis dizer echo ${set[@]}.
  • basta adicionar -w para grep para evitar palavras parciais

Resposta

Você poderia definir uma função bash para isso:

function word_valid() { if [ "$1" != "cat" -a "$1" != "dog" -a "$1" != "horse" ];then echo no else echo yes fi } 

Em seguida, use simplesmente assim:

word_valid cat 

Resposta

Eu estava procurando por uma solução “one line” para validar o argumento do meu script e usei a Joseph R. answer acima para vir up with:

[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }

Resposta

Você poderia usar fgrep para especificar todas as palavras permitidas:

if $(echo "$WORD" | fgrep -wq -e dog -e cat -e horse) ; then echo yes else echo no fi 

O sinalizador -w corresponde apenas a palavras inteiras, o -q a sinalização faz com que opere silenciosamente (porque tudo o que precisamos é o valor de retorno para a instrução if usar), e cada -e padrão especifica um padrão para permitir.

fgrep é a versão do grep que faz a correspondência de string normal em vez de correspondência de regex. Se você tiver grep, deverá ter fgrep, mas se não tiver, é “idêntico ao uso de grep com o sinalizador -F (então você apenas substituiria fgrep -wq acima por grep -Fwq).

Resposta

Isso funcionou para mim:

#!/bin/bash phrase=(cat dog parrot cow horse) findthis=parrot for item in ${phrase[*]} do test "$item" == "$findthis" && { echo "$findthis found!"; break; } done 

Resposta

Você pode querer colocar a lista de palavras em um arquivo, no caso de alterar a lista com frequência ou de desejar ser compartilhado por vários scripts. E pode ser necessário colocar as palavras em um arquivo se a lista ficar muito longa para gerenciar em um script. Em seguida, você pode dizer

if fgrep –qx "$WORD" word_list 

Comentários

  • não, eu não ‘ não quero ter minha lista em um arquivo

Resposta

Se as palavras são uma lista em que os valores são separados por uma nova linha, você pode fazer:

WORDS="$(ls -1)" if echo "${WORDS}" | grep --quiet --line-regexp --fixed-strings "${WORD}"; then echo yes else echo no fi 

Resposta

Acabei de ter o mesmo problema e encontrei uma solução surpreendentemente compreensível que não requer nenhum conhecimento de regex.

Observe que o A solução mostrada abaixo pode ser apenas bash, porque não tenho ideia sobre as diferenças entre o bash e outros shells. Além disso, o manual do bash avisa que esse tipo de correspondência de padrão é lento se a string que deve ser correspondida for longa.

WORD=abc [[ "$WORD" == @(def|abc|ghi|foo|barbaz) ]] && echo Word is in set. 

Como isso funciona?Não quero repetir grandes partes do manual do bash aqui, mas com minhas próprias palavras:

Se o operador binário == for usado com o comando composto [[, a palavra à direita do operador passa por correspondência de padrão, conforme explicado na seção ” Correspondência de padrão ” no manual do bash. Além disso, nessas condições, durante a correspondência, a opção de shell extglob é assumida como definida (independentemente da configuração real); o ponto-chave para entender o acima.

Mas e se as palavras em seu conjunto já contiverem caracteres que têm um significado especial na correspondência de padrões, substituição de comandos e outras expansões? O remédio é fácil: basta usar algo como

[[ "$WORD" == @("a*"|abc|"?ghi"|"$DontExpandMe"|barbaz) ]] && echo Word is in set. 

Achei muito fácil, compreensível e eficiente (contanto que $WORD seja curto) solução que não tem efeitos colaterais ou é da agudos como os métodos baseados em set.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *