Quero escrever uma função que verifique se uma determinada variável, digamos, var
começa com qualquer uma das palavras em uma determinada lista de strings. Esta lista não mudará.
Para instanciar, vamos fingir que quero verificar se var
começa aa
com abc
ou 3@3
.
Além disso, quero verificar se var
contém o caractere >
.
Digamos que esta função seja chamada check_func
. Meu uso pretendido é algo como
if check_func "$var"; then
do stuff
fi
Por exemplo, deveria "fazer coisas" para
aardvark
, abcdef
, [email protected]
e 12>5
.
eu tenho vistoesta pergunta SOonde um usuário fornece parte do trabalho:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Minha ideia é iterar a lista mencionada acima e usar essa função. Minha dificuldade reside em não entender exatamente como a saída (ou o que quer que substitua o retorno) deve ser feita para que isso funcione.
Responder1
check_prefixes () {
value=$1
for prefix in aa abc 3@3; do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
check_contains_gt () {
value=$1
case $value in
*">"*) return 0
esac
return 1
}
var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi
Dividi os testes em duas funções. Ambos usam case ... esac
e retornam sucesso (zero) assim que isso puder ser determinado. Se nada corresponder, a falha (1) será retornada.
Para tornar a lista de prefixos mais dinâmica, pode-se escrever a primeira função como
check_prefixes () {
value=$1
shift
for prefix do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
(o valor a ser inspecionado é o primeiro argumento, que salvamos value
e depois shift
retiramos da lista de argumentos da função; então iteramos sobre os argumentos restantes) e então o chamamos como
check_prefixes "$var" aa abc 3@3
A segunda função poderia ser alterada de maneira semelhante, para
check_contains () {
value=$1
shift
case $value in
*"$1"*) return 0
esac
return 1
}
(para verificar alguma substring arbitrária), ou
check_contains_oneof () {
value=$1
shift
for substring do
case $value in
*"$substring"*) return 0
esac
done
return 1
}
(para verificar qualquer uma de várias substrings)
Responder2
Para festa:
Usando as propriedades do regex você pode escrever start
com ^
e contain
por nada.
A lista de regexes a serem verificadascomeçarcom aa
abc
ou 3@3
econtém >
é:
^aa ^abc ^3@3 >
Faça disso umapropriadamentelista citada e peça ao bash para usar regexes ( =~
):
check_func() {
matched=1
for test_regex in '^aa' '^abc' '^3@3' '>'; do
if [[ $var =~ $test_regex ]] ; then
matched=0
break
fi
done
return "$matched"
}
var='aaIsAMatch'
if check_func; then
echo "A match was found"
fi
A função codificou a lista de correspondências e o nome da var.
Fornecendo a lista de regex em uma variável de array e o valor a ser testado no primeiro argumento:
check_func() {
local matched; matched=1
for t in "${test_regex[@]}"; do
[[ $1 =~ $t ]] && { matched=0; break; }
done
return "$matched"
}
test_regex=('^aa' '^abc' '^3@3' '>')
if check_func 'aaIsAMatch'; then
echo "A match was found"
fi
A função poderia ser melhorada para usar o nome de uma variável (em vez de um valor) como primeiro argumento.
posix
Como não há regex em shells posix e a única maneira de testar é uma instrução case, devemos usar uma instrução case. Infelizmente, para shells mais antigos ([nenhum globo estendido disponível][1]) devemos fazer um loop para fazer todos os testes. E os globos precisam ser:
'aa*' 'abc*' '3@3*' '*>*'
Um exemplo de script que testa diversas strings de entrada em vários globs:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; #break;; esac
echo "matched $value with $t"
;;
esac
done
return "$matched"
}
for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
echo "========A match was found for \"$var\""
fi
done
Uma versão mais simples da função para corresponder exatamente à sua solicitação:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; break;; esac
done
return "$matched"
}
Responder3
Veja o que a case
instrução faz: leve o segundo parâmetro para a função ( $2
). Se corresponder ao padrão "$1"*
, ou seja, o primeiro argumento da função seguido por qualquer coisa, execute true
e termine a case
instrução. true
não faz nada e retorna o status 0. Caso contrário, se corresponder *
, ou seja, qualquer coisa, execute false
e finalize a case
instrução. false
não faz nada e retorna o status 1. Assim, a case
instrução terá o status 0 se o segundo parâmetro começar com o primeiro parâmetro e 1 caso contrário. Como esta é a última (e única) instrução da função, a função retornará 0 se o segundo parâmetro começar com o primeiro parâmetro e 1 caso contrário.
Declarações condicionais, como if
no shell, consideram uma afirmação verdadeira se retornar 0 e falsa caso contrário. Portanto, if beginswith "$var" "string"; then echo yes; else echo no; fi
imprime yes
se o valor de var
começa com string
e no
caso contrário.
Existem várias maneiras alternativas de escrever esta função. Por exemplo, o autor poderia ter usado return 0
ou return 1
em vez de true
e false
, já que são a última instrução da função. A forma como a função foi escrita torna possível usar seu corpo diretamente, sem envolvê-la em uma função, apenas alterando as referências aos parâmetros da função ( $1
e $2
) para quaisquer strings com as quais você deseja trabalhar.
Para permitir vários prefixos, itere sobre eles em um loop. Assim que você encontrar um prefixo correspondente, retorne da função, com um status verdadeiro (0). Se nenhum dos prefixos corresponder, retorne um status falso (convencionalmente 1).
# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
string=$1
shift
for prefix in "$@"; do
case "$string" in
"$prefix"*) return 0;;
esac
done
return 1
}
if begins_with "$var" 'aa' 'abc' '3@3'; then
echo "The value starts with one of the permitted prefixes"
fi
Para testar um sufixo, use o padrão *"$suffix"
em vez de "$prefix"*
. Para testar uma substring, use *"$substring"*
. Observe que as aspas duplas são necessárias aqui, caso contrário a variável seria interpretada como um padrão. Por exemplo:
suffix='?'
case "$var" in
*"$suffix") echo "The value of var ends with a question mark";;
esac
case "$var" in
*$suffix) echo "The value of var is not empty";;
esac
Responder4
Revisado com base no esclarecimento da pergunta: Isso é menos elegante (e muito menos flexível), mas mais compacto que as outras respostas,
check_func() {
case "$1" in
( aa* | abc* | 3@3* | *">"*)
return 0
esac
return 1
}
Isso retorna verdadeiro para aardvark
, abcdef
e . E, claro, também , e .[email protected]
12>5
aard>vark
abc<def>ghi
3@3>3