No bash, como posso verificar se uma string começa com algum valor?

Eu gostaria de verificar se uma string começa com “nó”, por exemplo, “node001”. Algo como

if [ $HOST == user* ] then echo yes fi 

Como posso fazer isso corretamente?


Eu ainda preciso combinar expressões para verificar se o HOST é “user1” ou começa com “node”

 if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi > > > -bash: [: too many arguments 

Como fazer isso corretamente?

Este snippet no Guia Avançado de Script Bash diz:

 # The == comparison operator behaves differently within a double-brackets # test than within single brackets. [[ $a == z* ]] # True if $a starts with a "z" (wildcard matching). [[ $a == "z*" ]] # True if $a is equal to z* (literal matching). 

Então você tinha quase correto; você precisava de colchetes duplos , não de colchetes únicos.


Com relação à sua segunda pergunta, você pode escrever desta maneira:

 HOST=user1 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes1 fi HOST=node001 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes2 fi 

Que vai ecoar

 yes1 yes2 

Bash if syntax é difícil de se acostumar (IMO).

Se você estiver usando uma recente bash (v3 +) sugira bash regex comparison operator =~ , ie

 if [[ "$HOST" =~ ^user.* ]]; then echo "yes" fi 

Para combinar this or that em um uso regex | ou seja

 if [[ "$HOST" =~ ^user.*|^host1 ]]; then echo "yes" fi 

Nota – esta é a syntax de expressão regular ‘adequada’.

  • user* significa use e zero ou mais ocorrências de r , então use e userrrr corresponderá.
  • user.* significa user e zero ou mais ocorrências de qualquer caractere, então user1 , userX corresponderá.
  • ^user.* significa corresponder ao user.* padrão user.* no início de $ HOST.

Se você não estiver familiarizado com a syntax da expressão regular, tente se referir a esse recurso .

Nota – é melhor se você perguntar a cada nova pergunta como uma nova pergunta, tornar o stackoverflow mais arrumado e mais útil. Você sempre pode include um link para uma pergunta anterior para referência.

Eu sempre tento ficar com POSIX sh em vez de usar extensões bash, já que um dos principais pontos de script é a portabilidade. (Além de conectar programas, não substituí-los)

Em sh, há uma maneira fácil de verificar uma condição “é-prefixo”.

 case $HOST in node*) your code here esac 

Dada a idade, arca e crufty sh é (e bash não é a cura: é mais complicado, menos consistente e menos portável), eu gostaria de destacar um aspecto funcional muito bom: enquanto alguns elementos de syntax como case são construídos in, as construções resultantes não são diferentes de qualquer outro trabalho. Eles podem ser compostos da mesma maneira:

 if case $HOST in node*) true;; *) false;; esac; then your code here fi 

Ou ainda mais curto

 if case $HOST in node*) ;; *) false;; esac; then your code here fi 

Ou ainda mais curto (apenas para apresentar ! Como um elemento de linguagem – mas agora é um estilo ruim)

 if ! case $HOST in node*) false;; esac; then your code here fi 

Se você gosta de ser explícito, crie seu próprio elemento de linguagem:

 beginswith() { case $2 in "$1"*) true;; *) false;; esac; } 

Isso não é realmente muito bom?

 if beginswith node "$HOST"; then your code here fi 

E como sh é basicamente apenas jobs e listas de strings (e internamente processos, dos quais jobs são compostos), agora podemos até fazer alguma functional programming light:

 beginswith() { case $2 in "$1"*) true;; *) false;; esac; } checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; } all() { test=$1; shift for i in "$@"; do $test "$i" || return done } all "beginswith x" x xy xyz ; checkresult # prints TRUE all "beginswith x" x xy abc ; checkresult # prints FALSE 

Isso é elegante. Não que eu defenda o uso do sh para algo sério – ele quebra muito rapidamente os requisitos do mundo real (não lambdas, portanto, deve usar strings. Mas aninhar chamadas de function com strings não é possível, pipes não são possíveis …)

Você pode selecionar apenas a parte da string que deseja verificar:

 if [ ${HOST:0:4} = user ] 

Para sua pergunta de acompanhamento, você pode usar um OR :

 if [[ $HOST == user1 || $HOST == node* ]] 

Eu prefiro os outros methods já postados, mas algumas pessoas gostam de usar:

 case "$HOST" in user1|node*) echo "yes";; *) echo "no";; esac 

Editar:

Eu adicionei seus suplentes à declaração de caso acima

Na sua versão editada, você tem muitos colchetes. Deve ficar assim:

 if [[ $HOST == user1 || $HOST == node* ]]; 

desde # tem um significado na bash eu cheguei à seguinte solução.
Além disso, gosto de empacotar cordas com “” para superar espaços, etc.

 A="#sdfs" if [[ "$A" == "#"* ]];then echo "skip comment line" fi 

Embora eu ache a maioria das respostas aqui corretas, muitas delas contêm bashisms desnecessários. A expansão do parâmetro POSIX oferece tudo o que você precisa:

 [ "${host#user}" != "${host}" ] 

e

 [ "${host#node}" != "${host}" ] 

${var#expr} retira o menor prefixo correspondente expr de ${var} e retorna isso. Portanto, se ${host} não iniciar com o user ( node ), ${host#user} ( ${host#node} ) será o mesmo que ${host} .

expr permite curingas fnmatch() , assim ${host#node??} e os amigos também trabalham.

@OP, para ambas as suas dúvidas você pode usar case / esac

 string="node001" case "$string" in node*) echo "found";; * ) echo "no node";; esac 

segunda questão

 case "$HOST" in node*) echo "ok";; user) echo "ok";; esac case "$HOST" in node*|user) echo "ok";; esac 

OU Bash 4.0

 case "$HOST" in user) ;& node*) echo "ok";; esac 
 if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi 

não funciona, porque todos [ , [[ e teste reconhecem a mesma gramática não-recursiva. veja a seção EXPRESSÕES CONDICIONAIS na sua página man bash.

Como um aparte, o SUSv3 diz

O comando condicional derivado do KornShell (colchete duplo [[]] ) foi removido da descrição do idioma do comando shell em uma proposta inicial. Objeções foram levantadas que o problema real é o uso incorreto do comando de teste ( [ ), e colocá-lo no shell é a maneira errada de corrigir o problema. Em vez disso, documentação adequada e uma nova palavra reservada shell ( ! ) São suficientes.

Testes que exigem várias operações de teste podem ser feitos no nível do shell usando invocações individuais do comando de teste e lógicas do shell, em vez de usar o sinalizador -o de teste propenso a erros.

você precisaria escrever dessa maneira, mas o teste não suporta:

 if [ $HOST == user1 -o $HOST == node* ]; then echo yes fi 

usos de teste = para igualdade de strings, mais importante, não suporta correspondência de padrões.

case / esac tem um bom suporte para correspondência de padrões:

 case $HOST in user1|node*) echo yes ;; esac 

tem o benefício adicional de não depender de bash, a syntax é portátil. da Especificação Unix Única, A Linguagem de Comandos do Shell:

 case word in [(]pattern1) compound-list;; [[(]pattern[ | pattern] ... ) compound-list;;] ... [[(]pattern[ | pattern] ... ) compound-list] esac 

Adicionando um pouco mais de detalhes de syntax à resposta mais alta de Mark Rushakoff.

A expressão

 $HOST == node* 

Também pode ser escrito como

 $HOST == "node"* 

O efeito é o mesmo. Apenas certifique-se de que o caractere curinga esteja fora do texto citado. Se o curinga estiver dentro das aspas, ele será interpretado literalmente (ou seja, não como curinga).

Outra coisa que você pode fazer é eliminar o que está ecoando e canalizar com o inline cut -c 1-1inline cut -c 1-1