Come verificare se una stringa contiene una sottostringa in Bash
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.
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 busybox :
[ -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 bash , trattino , ksh e ash (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 busybox , trattino e, naturalmente, bash :
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
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
}