Verifica se una stringa contiene una sottostringa


40

Ho il codice

file="JetConst_reco_allconst_4j2t.png"
if [[ $file == *_gen_* ]];
then
    echo "True"
else
    echo "False"
fi

Provo se filecontiene "gen". L'output è "False". Bello!

Il problema è quando sostituisco "gen" con una variabile testseq:

file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file == *_$testseq_* ]];
then
    echo "True"
else
    echo "False"
fi

Ora l'output è "True". Come potrebbe essere? Come risolvere il problema?


Risposte:


25

Devi interpolare la $testseqvariabile con uno dei seguenti modi:

  • $file == *_"$testseq"_*(qui $testseqconsiderato come una stringa fissa)

  • $file == *_${testseq}_*(qui $testseqconsiderato come un modello).

O _immediatamente dopo il nome della variabile verrà preso come parte del nome della variabile (è un carattere valido in un nome di variabile).


Risposta corretta come si applica a OP, ma senza essere portatile. (Questa non è una critica alla risposta fornita, solo un avvertimento per i lettori). ;-)
Cbhihe,

28

Utilizzare l' =~operatore per fare confronti tra espressioni regolari:

#!/bin/bash
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file =~ $testseq ]];
then
    echo "True"
else
    echo "False"
fi

In questo modo, confronterà se $fileha $testseqsul suo contenuto.

user@host:~$ ./string.sh
False

Se cambio testseq="Const":

user@host:~$ ./string.sh
True

Ma fai attenzione a ciò di cui ti nutri $testseq. Se la stringa su di essa in qualche modo rappresenta una regex (come [0-9]ad esempio), ci sono più possibilità di innescare una "corrispondenza".

Riferimento :


20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

L'utilizzo case ... esacè uno dei modi più semplici per eseguire una corrispondenza del modello in modo portatile. Funziona come una dichiarazione di "switch" in altre lingue ( bash, zsh, e ksh93permette anche di fare cadere-through in vari modi incompatibili). I pattern utilizzati sono i pattern globbing del nome file standard.

Il problema riscontrato è dovuto al fatto che _è un carattere valido in un nome di variabile. La shell vedrà quindi *_$testseq_*come " *_seguito dal valore della variabile $testseq_e un *". La variabile $testseq_non è definita, quindi verrà espansa in una stringa vuota e alla fine *_*, che ovviamente corrisponde al $filevalore che hai. Potresti aspettarti di ottenere Truefino a quando il nome file $filecontiene almeno un carattere di sottolineatura.

Per delimitare correttamente il nome della variabile, l'uso "..."in tutto l'espansione: *_"$testseq"_*. Questo userebbe il valore della variabile come stringa. Vorresti usare il valore della variabile come modello , usa *_${testseq}_*invece.

Un'altra soluzione rapida è quella di includere i trattini bassi nel valore di $testseq:

testseq="_gen_"

e quindi basta usare *"$testseq"*come modello (per un confronto di stringhe).


Quindi la shell cercherà una variabile $ testseq_, non la troverà e la sostituirà con una stringa vuota.
Viesturs,

@Viesturs Questo è il nocciolo del problema, sì.
Kusalananda

1
Per una stringa di ricerca che dovrebbe essere *"$testseq"*per casecome per [[...]](tranne che per zsh a meno che non si attiva globsubst)
Stéphane Chazelas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.