Domanda La stringa contiene una sottostringa in Bash


Ho una stringa in Bash:

string="My string"

Come posso testare se contiene un'altra stringa?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Dove ?? è il mio operatore sconosciuto. Io uso echo e grep?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Sembra un po 'goffo.


1740
2017-10-23 12:37


origine


risposte:


Puoi usare La risposta di Marcus (* caratteri jolly) anche all'esterno di un'istruzione case, se si usano parentesi doppie:

string='My long string'
if [[ $string = *"My long"* ]]; then
  echo "It's there!"
fi

Si noti che gli spazi nella stringa dell'ago devono essere posizionati tra virgolette doppie e * i caratteri jolly dovrebbero essere all'esterno.


2485
2017-10-23 12:55



Se preferisci l'approccio regex:

string='My string';

if [[ $string =~ .*My.* ]]
then
   echo "It's there!"
fi

386
2017-10-23 20:10



Non sono sicuro di utilizzare un'istruzione if, ma è possibile ottenere un effetto simile con un'istruzione case:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

239
2017-10-23 12:47



Risposta compatibile

Poiché ci sono già molte risposte usando le funzionalità specifiche di Bash, c'è un modo per lavorare con shell con caratteristiche più povere, come :

[ -z "${string##*$reqsubstr*}" ]

In pratica, ciò potrebbe dare:

string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
  if [ -z "${string##*$reqsubstr*}" ] ;then
      echo "String '$string' contain substring: '$reqsubstr'."
    else
      echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
  done

Questo è stato testato sotto , ,  e  (busybox), e il risultato è sempre:

String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.

In una funzione

Come richiesto da @EeroAtonton, ecco una versione della stessa demo, testata con le stesse shell:

myfunc() {
    reqsubstr="$1"
    shift
    string="$@"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'." 
    fi
}

Poi:

$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.

$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.

Avviso: devi sfuggire o raddoppiare le virgolette e / o le doppie virgolette:

$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.

$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.

Funzione semplice

Questo è stato testato sotto ,  e naturalmente :

stringContain() { [ -z "${2##*$1*}" ]; }

È tutto gente!

Quindi ora:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes

... O se la stringa inviata potrebbe essere vuota, come indicato da @Sjlver, la funzione diventerebbe:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

o come suggerito da Il commento di Adrian Günter, evitando -o switche:

stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ] ;} ; }

Con stringhe vuote:

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

135
2017-12-08 23:06



Dovresti ricordare che lo scripting della shell è meno di una lingua e più di una collezione di comandi. Istintivamente pensi che questo "linguaggio" richieda di seguire un if con un [ o a [[. Entrambi sono solo comandi che restituiscono uno stato di uscita che indica il successo o il fallimento (proprio come ogni altro comando). Per questo motivo lo userei grepe non il [ comando.

Basta fare:

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Ora che stai pensando if come testare lo stato di uscita del comando che lo segue (completo di punto e virgola). Perché non riconsiderare la fonte della stringa che stai testando?

## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...

## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...

Il -q l'opzione fa in modo che grep non produca nulla, poiché vogliamo solo il codice di ritorno. <<< rende la shell espandere la parola successiva e usarla come input per il comando, una versione a una riga di << qui documento (non sono sicuro se questo è standard o un bashismo).


110
2017-10-27 14:57



La risposta accettata è la migliore, ma poiché c'è più di un modo per farlo, ecco un'altra soluzione:

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace} è $var con la prima istanza di search sostituito da replace, se viene trovato (non cambia $var). Se provi a sostituire foo da niente, e la stringa è cambiata, quindi ovviamente foo è stato trovato.


73
2017-10-23 14:35



Quindi ci sono molte soluzioni utili alla domanda - ma quale è la più veloce / usa la minima risorsa?

Test ripetuti usando questo frame:

/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'

Sostituire TEST ogni volta:

[[ $b =~ $a ]]           2.92user 0.06system 0:02.99elapsed 99%CPU

[ "${b/$a//}" = "$b" ]   3.16user 0.07system 0:03.25elapsed 99%CPU

[[ $b == *$a* ]]         1.85user 0.04system 0:01.90elapsed 99%CPU

case $b in *$a):;;esac   1.80user 0.02system 0:01.83elapsed 99%CPU

doContain $a $b          4.27user 0.11system 0:04.41elapsed 99%CPU

(doContain era nella risposta di F. Houri)

E per le risate:

echo $b|grep -q $a       12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!

Quindi, la semplice opzione di sostituzioni vince in modo prevedibile sia in un test esteso che in un caso. Il caso è portatile.

Piping out to 100000 greps è prevedibilmente doloroso! La vecchia regola sull'utilizzo di utilità esterne senza necessità è vera.


31
2017-08-27 19:42



Questo funziona anche:

if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  printf "Found needle in haystack"
fi

E il test negativo è:

if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  echo "Did not find needle in haystack"
fi

Suppongo che questo stile sia un po 'più classico, meno dipendente dalle caratteristiche della shell di Bash.

Il -- l'argomento è pura paranoia POSIX, usata per proteggere da stringhe di input simili alle opzioni, come ad esempio --abc o -a.

Nota: in un ciclo ristretto questo codice sarà tanto più lento dell'utilizzo delle funzioni di shell Bash interne, in quanto uno o due processi separati verranno creati e collegati tramite pipe.


22
2017-12-01 15:41