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
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á seWORD=ca
ouWORD=og
ou semelhante e suponho que você quis dizerecho ${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
.
shopt -s nocasematch
pode ajudar se você quiser que a pesquisa não faça distinção entre maiúsculas e minúsculas.[[
e]]
–[
e]
não são suficientes.[[ "$ARG" =~ ^(true|false)$ ]] || { echo "Argument received invalid value" ; exit 1 ; }
egrep -q "^$WORD$" /tmp/words; [[ $? != 0 ]] && echo "Not found" || echo "OK"
.