Domanda

Ho una stringa in Bash:

string="My string"

Come posso verificare se contiene un'altra stringa?

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

Dove ?? è il mio operatore sconosciuto. Uso echo e grep?

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

Sembra un po 'goffo.

È stato utile?

Soluzione

Puoi utilizzare la risposta di Marcus (* caratteri jolly) anche al di fuori di un'istruzione case, se usi parentesi doppie:

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

Nota che gli spazi nella stringa dell'ago devono essere posizionati tra virgolette doppie e che i * caratteri jolly devono essere esterni.

Altri suggerimenti

Se preferisci l'approccio regex:

string='My string';

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

Non sono sicuro di usare un'istruzione if, ma puoi ottenere un effetto simile con un'istruzione case:

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

Risposta compatibile

Dato che ci sono già molte risposte usando le funzionalità specifiche di Bash, c'è un modo di lavorare con shell con funzionalità scadenti, come :

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

In pratica, questo 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 in , , 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 @EeroAaltonen 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
}

Quindi:

$ 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 scappare o racchiudere tra virgolette e / o virgolette doppie:

$ 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 in , e, naturalmente, :

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

Questo è 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 potesse essere vuota, come indicato da @Sjlver, la funzione diventerebbe:

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

o come suggerito da Adrian G & # 252; commento di 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

Dovresti ricordare che gli script di shell sono meno di una lingua e più di una raccolta di comandi. Istintivamente pensi che questo & Quot; lingua & Quot; richiede di seguire un if con un [ o un [[. Entrambi sono solo comandi che restituiscono uno stato di uscita che indica l'esito positivo o negativo (proprio come ogni altro comando). Per questo motivo userei grep e non il comando -q.

Basta fare:

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

Ora che stai pensando a <<< come testare lo stato di uscita del comando che lo segue (completo di punti e virgola). Perché non riconsiderare l'origine 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
#...

L'opzione << fa in modo che grep non emetta nulla, poiché vogliamo solo il codice di ritorno. <=> fa in modo che la shell espanda la parola successiva e la usi come input per il comando, una versione di una riga del documento <=> qui (non sono sicuro che sia standard o bashism).

La risposta accettata è la migliore, ma poiché esiste 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 sostituita da replace, se viene trovata (non cambia foo). Se provi a sostituire <=> per nulla e la stringa è cambiata, ovviamente <=> è stato trovato.

Quindi ci sono molte soluzioni utili alla domanda, ma qual è la più veloce / utilizza la minor 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'

Sostituendo 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 risatine:

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

Quindi la semplice opzione di sostituzione sostituisce prevedibilmente se in un test esteso o in un caso. Il caso è portatile.

Prevedere fino a 100000 greps è prevedibilmente doloroso! La vecchia regola sull'uso di utility esterne senza necessità è vera.

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 funzionalità della shell Bash.

L'argomento -- è pura paranoia POSIX, utilizzata per proteggere da stringhe di input simili alle opzioni, come --abc o -a.

Nota: in un ciclo stretto questo codice sarà molto più lento rispetto all'utilizzo delle funzionalità interne della shell Bash, poiché uno (o due) processi separati verranno creati e collegati tramite pipe.

Che ne dici di questo:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi

Bash4 + esempi. Nota: non usare le virgolette causerà problemi quando le parole contengono spazi, ecc. Citare sempre in IMO bash.

Ecco alcuni esempi BASH4 +:

Esempio 1, controlla 'yes' nella stringa (senza distinzione tra maiuscole e minuscole):

    if [[ "${str,,}" == *"yes"* ]] ;then

Esempio 2, controlla 'yes' nella stringa (senza distinzione tra maiuscole e minuscole):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Esempio 3, controlla 'yes' nella stringa (case sensitive):

     if [[ "${str}" == *"yes"* ]] ;then

Esempio 4, controlla 'yes' nella stringa (case sensitive):

     if [[ "${str}" =~ "yes" ]] ;then

Esempio 5, corrispondenza esatta (maiuscole e minuscole):

     if [[ "${str}" == "yes" ]] ;then

Esempio 6, corrispondenza esatta (senza distinzione tra maiuscole e minuscole):

     if [[ "${str,,}" == "yes" ]] ;then

Esempio 7, corrispondenza esatta:

     if [ "$a" = "$b" ] ;then

Esempio 8, corrispondenza jolly .ext (senza distinzione tra maiuscole e minuscole):

     if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then

godere.

Come menzionato da Paul nel suo confronto delle prestazioni:

if echo "abcdefg" | grep -q "bcdef"; then
    echo "String contains is true."
else
    echo "String contains is not true."
fi

Questo è conforme a POSIX come il 'case " $ string " nella risposta fornita da Marcus, ma è leggermente più facile da leggere rispetto alla risposta dell'istruzione case. Nota anche che questo sarà molto più lento rispetto all'uso di un'istruzione case, come ha sottolineato Paul, non usarlo in un ciclo.

Questo stack & nbsp; risposta di overflow è stato l'unico a intercettare i caratteri di spazio e trattino:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found

Uno è:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

grep -q è utile a questo scopo.

Lo stesso usando awk:

string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Output:

  

Non trovato

string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Output:

  

Trovato

Fonte originale: http: // unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html

Mi piace sed.

substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1

Modifica, Logica:

  • Usa sed per rimuovere l'istanza di sottostringa dalla stringa

  • Se la nuova stringa differisce dalla vecchia stringa, esiste una sottostringa

Il mio .bash_profile e come ho usato grep se il PERCORSO includeva le mie 2 directory bin, non aggiungerle

# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

U=~/.local.bin:~/bin

if ! echo "$PATH" | grep -q "home"; then
    export PATH=$PATH:${U}   
fi

Ho scoperto di aver bisogno di questa funzionalità abbastanza frequentemente, quindi sto usando una funzione shell fatta in casa nel mio .bashrc come questa che mi permette di riutilizzarla tutte le volte che ho bisogno, con un facile da ricordare nome:

function stringinstring()
{
    case "$2" in 
       *"$1"*)
          return 0
       ;;
    esac   
    return 1
}

Per verificare se $string1 (diciamo, abc ) è contenuto in $string2 (diciamo, 123abcABC ) devo solo eseguire stringinstring "$string1" "$string2" e controllare il valore restituito, ad esempio

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO

Prova oobash è una libreria di stringhe in stile OO per bash 4. Ha il supporto per le umlaut tedesche. È scritto in bash. Sono disponibili molte funzioni: -base64Decode , -base64Encode , -capitalize , -center , -charAt , -concat , -contains , -count , -endsWith , -equals , -equalsIgnoreCase , -reverse , -hashCode , -indexOf , -isAlnum , -isAlpha , -isAscii , -isDigit , -isEmpty , -isHexDigit , -isLowerCase , -isSpace , -isPrintable , -isUpperCase , -isVisible , -lastIndexOf , -length , -matches , -replaceAll , -replaceFirst , -startWith , -substring , -swapCase , -toLowerCase , -toString , -toUpperCase , -trim e -zfill .

Guarda l'esempio contiene:

[Desktop]$ String a testXccc                                                  
[Desktop]$ a.contains tX                   
true                                                           
[Desktop]$ a.contains XtX      
false      

oobash è disponibile su Sourceforge.net .

Corrispondenza esatta della parola:

string='My long string'
exactSearch='long'

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi

Estensione della domanda qui fornita https://stackoverflow.com/a/8811800/712666

Questa soluzione funziona con caratteri speciali:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"

    if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"

contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"

Uso questa funzione (una dipendenza non inclusa ma ovvia). Supera i test mostrati di seguito. Se la funzione restituisce un valore > 0 quindi la stringa è stata trovata. Potresti restituire altrettanto facilmente 1 o 0.

function str_instr {
   # Return position of ```str``` within ```string```.
   # >>> str_instr "str" "string"
   # str: String to search for.
   # string: String to search.
   typeset str string x
   # Behavior here is not the same in bash vs ksh unless we escape special characters.
   str="$(str_escape_special_characters "${1}")"
   string="${2}"
   x="${string%%$str*}"
   if [[ "${x}" != "${string}" ]]; then
      echo "${#x} + 1" | bc -l
   else
      echo 0
   fi
}

function test_str_instr {
   str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
   str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
   str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
   str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
   str_instr "a" "abc" | assert_eq 1
   str_instr "z" "abc" | assert_eq 0
   str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
   str_instr "a" "" | assert_eq 0
   str_instr "" "" | assert_eq 0
   str_instr " " "Green Eggs" | assert_eq 6
   str_instr " " " Green "  | assert_eq 1
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top