Eu tenho o código
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
Eu testo se file
contém “gen”. A saída é “False”. Legal!
O problema é quando substituo “gen” por uma variável testseq
:
file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi
Agora a saída é “True”. Como isso poderia ser? Como resolver o problema?
Comentários
- Possível duplicata de Teste de shell para encontrar um padrão em uma string
Resposta
Você precisa interpolar o $testseq
variável com uma das seguintes maneiras:
-
$file == *_"$testseq"_*
(aqui$testseq
considerado como uma string fixa) -
$file == *_${testseq}_*
(aqui$testseq
considerado como um padrão).
Ou _
imediatamente após o nome da variável “s será considerado como parte da variável” s nome (é um caractere válido em um nome de variável).
Comentários
- Resposta correta, pois se aplica ao OP, mas não é portátil . (Esta não é uma crítica à resposta fornecida, apenas um aviso aos leitores). 😉
Resposta
Use a operação =~
ou para fazer comparações de expressões regulares:
#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi
Dessa forma, ele comparará se $file
tiver $testseq
em seu conteúdo.
user@host:~$ ./string.sh False
Se eu mudar testseq="Const"
:
user@host:~$ ./string.sh True
Mas, tome cuidado com o que você alimenta $testseq
. Se a string nele representa de alguma forma um regex (como [0-9]
por exemplo), há uma chance maior de acionar uma “correspondência”.
Referência :
Comentários
- Parece que esta resposta é para " bash " apenas
Resposta
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Usar case ... esac
é uma das maneiras mais simples de realizar uma correspondência de padrão de forma portátil. Funciona como uma instrução “switch” em outros idiomas (bash
, zsh
e ksh93
também permite que você faça fall-through de várias maneiras incompatíveis). Os padrões usados são os padrões de globbing de nome de arquivo padrão.
O problema que você está tendo é devido ao fato de que _
é um caractere válido em um nome de variável. O shell, portanto, verá *_$testseq_*
como “*_
seguido pelo valor da variável $testseq_
e um *
“. A variável $testseq_
é indefinida, então ela será expandida para uma string vazia e você acabará com *_*
, que obviamente corresponde a $file
valor que você tem. Você pode esperar obter True
, desde que o nome do arquivo em $file
contenha pelo menos um sublinhado.
Para adequadamente delimite o nome da variável, use "..."
em torno da expansão: *_"$testseq"_*
. Isso usaria o valor da variável como uma string. Se você quiser usar o valor da variável como um padrão , use *_${testseq}_*
em vez disso.
Outra solução rápida é incluir o sublinhados no valor de $testseq
:
testseq="_gen_"
e, em seguida, basta usar *"$testseq"*
como o padrão (para uma comparação de string).
Comentários
- Portanto, o shell estará procurando por uma variável $ testseq_ e não encontrará e substitua-o por uma string vazia.
- @Viesturs Que ' s é o cerne da questão, sim.
- Para um a pesquisa de substring deve ser
*"$testseq"*
paracase
como para[[...]]
(exceto para zsh, a menos que você enable globsubst) - Mais simples do que ?
- @Isaac Em termos de leitura e compreensão do que ' está acontecendo, sim. É ' também fácil estender um teste com mais casos de teste sem obter um " if-then-elif-then-elif " espaguete. Embora teste uma única string, a maneira como você mostra (se uma string desaparece em uma substituição) é mais curta.
Resposta
Para a forma portátil de testar se uma string contém uma substring, use:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Ou "${file##*"$testseq"*}"
para evitar interpretar caracteres glob em testseq
.
Comentários
- Você ' d precisa de algo como [" $ {file ## * $ testseq *} "! = " $ file " ] porque no traço que é Remover o maior padrão de prefixo.
- Não, @NoelGrandin não há mudança na maioria dos shells (incluindo o traço), o Padrão do maior prefixo será a string inteira se o valor do subpadrão da variável (
$testseq
) estiver contido no valor$file
. Tente:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'
para confirmar que o traço removerá toda a string.