Jak sprawdzić, czy łańcuch zawiera podłańcuch w Bash
Mam string w Bash:
string="My string"
Jak mogę sprawdzić, czy zawiera inny ciąg znaków?
if [ $string ?? 'foo' ]; then
echo "It's there!"
fi
Gdzie ??
jest mój nieznany operator. Czy używam echo i grep
?
if echo "$string" | grep 'foo'; then
echo "It's there!"
fi
To wygląda trochę niezdarnie. 21 answers
Możesz użyć Marcus ' s answer (*wildcards) poza instrukcją case, również, jeśli używasz podwójnych nawiasów:
string='My long string'
if [[ $string == *"My long"* ]]; then
echo "It's there!"
fi
Zauważ, że spacje w łańcuchu igieł muszą być umieszczone pomiędzy podwójnymi cudzysłowami, a *
symbole wieloznaczne powinny znajdować się na zewnątrz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 14:14:14
Jeśli wolisz podejście regex:
string='My string';
if [[ $string =~ .*My.* ]]
then
echo "It's there!"
fi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 20:10:53
Nie jestem pewien co do użycia instrukcji if, ale można uzyskać podobny efekt za pomocą instrukcji case:
case "$string" in
*foo*)
# Do stuff
;;
esac
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 12:47:04
Zgodna odpowiedź
Ponieważ istnieje już wiele odpowiedzi wykorzystujących funkcje specyficzne dla Basha, istnieje sposób pracy pod uboższymi powłokami, takimi jak busybox :
[ -z "${string##*$reqsubstr*}" ]
W praktyce może to dać:
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
To zostało przetestowane pod bash, dash, ksh i ash (busybox), a wynik jest zawsze:
String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.
W jedną funkcję
Jak zapytał @EeroAaltonen oto wersja tego samego demo, testowane pod tymi samymi muszlami:
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
}
Potem:
$ 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'.
Notice: musisz escape lub Double enclose cudzysłów i / lub podwójne cudzysłowy:
$ 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'.
Prosta funkcja
To zostało przetestowane pod busybox, dash i oczywiście bash :
stringContain() { [ -z "${2##*$1*}" ]; }
To wszystko!
Then now:
$ 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
... Lub jeśli podany ciąg znaków może być pusty, jak wskazuje @Sjlver, funkcja zostań:
stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }
Lub zgodnie z sugestią komentarz Adriana Güntera , unikając -o
switche:
stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ] ;} ; }
Z pustymi łańcuchami:
$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 06:35:38
Należy pamiętać, że skrypty powłoki są mniej językiem, a bardziej zbiorem poleceń. Instynktownie myślisz, że ten "język" wymaga podążania za if
z [
lub [[
. Oba są po prostu poleceniami, które zwracają status zakończenia wskazujący na sukces lub porażkę (tak jak każde inne polecenie). Z tego powodu użyłbym grep
, a nie [
polecenia.
Po prostu zrób:
if grep -q foo <<<"$string"; then
echo "It's there"
fi
Teraz, gdy myślisz o if
jako o sprawdzaniu statusu wyjścia z polecenie, które następuje po nim (wraz z dwukropkiem). Dlaczego nie przemyśleć źródła łańcucha, który testujesz?
## 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
#...
Opcja -q
sprawia, że grep nie wyświetla niczego, ponieważ chcemy tylko kodu zwrotnego. <<<
sprawia, że powłoka rozszerza następne słowo i używa go jako wejścia do polecenia, jednowierszowej wersji <<
tutaj dokumentu (nie jestem pewien, czy jest to standard, czy bashism).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 06:41:24
Przyjęta odpowiedź jest najlepsza, ale ponieważ istnieje więcej niż jeden sposób, oto inne rozwiązanie:
if [ "$string" != "${string/foo/}" ]; then
echo "It's there!"
fi
${var/search/replace}
jest {[2] } z pierwszą instancją search
zastąpioną przez replace
, jeśli zostanie znaleziona(nie zmienia się $var
). Jeśli spróbujesz zastąpić foo
przez nic, a łańcuch znaków się zmienił, to oczywiście foo
został znaleziony.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-12 05:33:48
Więc jest wiele przydatnych rozwiązań na pytanie - ale który jest najszybszy / wykorzystuje najmniej zasobów?
Testy powtarzane przy użyciu tej ramki:
/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'
Test zastępczy za każdym razem:
[[ $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 był w odpowiedzi F. Houriego)
I dla chichotów:
echo $b|grep -q $a 12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!
Tak więc prosta opcja podstawienia predykatalnie wygrywa, czy w rozszerzonym teście, czy w przypadku. Walizka jest przenośna.
Przelot do 100000 grepów jest przewidywalnie bolesny! Stara zasada o używaniu narzędzia zewnętrzne bez potrzeby.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-27 19:42:38
To również działa:
if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
printf "Found needle in haystack"
fi
A test negatywny to:
if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
echo "Did not find needle in haystack"
fi
Przypuszczam, że ten styl jest nieco bardziej klasyczny -- mniej zależny od funkcji powłoki Bash.
Argument --
to czysty POSIX, używany do ochrony przed ciągami wejściowymi podobnymi do opcji, takich jak --abc
czy -a
.
Uwaga: w ciasnej pętli kod ten będzie dużo wolniejszy niż używanie wewnętrznych funkcji powłoki Bash, ponieważ jeden (lub dwa) oddzielne procesy będą tworzone i połączone za pomocą rury.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-11 23:53:20
A może tak:
text=" <tag>bmnmn</tag> "
if [[ "$text" =~ "<tag>" ]]; then
echo "matched"
else
echo "not matched"
fi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-15 16:37:57
Ta odpowiedź przepełnienia stosu była jedyną, która zatrzymała znaki spacji i kreski:
# For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:48
Jak wspomniał Paweł w swoim porównaniu wydajności:
if echo "abcdefg" | grep -q "bcdef"; then
echo "String contains is true."
else
echo "String contains is not true."
fi
Jest to zgodne ze standardem POSIX, podobnie jak' case '$string ' in 'answer dostarczone przez Marcusa, ale jest nieco łatwiejsze do odczytania niż case' s statement answer. Zauważ również, że będzie to znacznie wolniejsze niż użycie instrukcji case, jak zauważył Paul, nie używaj jej w pętli.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-31 22:32:14
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 19:55:58
Jeden to:
[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 17:31:54
grep -q
jest przydatny w tym celu.
To samo za pomocą awk
:
string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Wyjście:
Nie Znaleziono
string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Wyjście:
Znaleziono
Oryginalne źródło: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-28 16:54:12
Lubię sed.
substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1
Edit, Logic:
-
Użyj sed, aby usunąć instancję podłańcucha z łańcucha
-
Jeśli nowy łańcuch różni się od Starego, istnieje podłańcuch
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-05 14:42:02
Mój .bash_profile i jak korzystałem z grepa jeśli ścieżka zawiera Moje 2 bin dirs, nie dołączaj ich
# .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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-14 05:36:44
Uznałem, że ta funkcjonalność jest potrzebna dość często, więc używam domowej funkcji powłoki w moim .bashrc
, takiej jak ta, która pozwala mi ponownie używać jej tak często, jak muszę, z łatwą do zapamiętania nazwą: {]}
function stringinstring()
{
case "$2" in
*"$1"*)
return 0
;;
esac
return 1
}
Aby sprawdzić czy $string1
(powiedzmy, abc) jest zawarte w $string2
(powiedzmy, 123abcabc) wystarczy uruchomić stringinstring "$string1" "$string2"
i sprawdzić wartość zwracaną, na przykład
stringinstring "$str1" "$str2" && echo YES || echo NO
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-11 18:09:46
Spróbuj Oobash jest to biblioteka ciągów w stylu oo dla bash 4. Ma poparcie dla niemieckich umlautów. Jest napisany w bash. Dostępnych jest wiele funkcji: -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
, -startsWith
, -substring
, -swapCase
, -toLowerCase
, -toString
, -toUpperCase
, -trim
, i -zfill
.
Zobacz też przykład:
[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-08 15:03:21
Dokładne dopasowanie słów:
string='My long string'
exactSearch='long'
if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
then
echo "It's there"
fi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 14:56:18
Używam tej funkcji(jedna zależność nie jest uwzględniona, ale oczywista). Przechodzi testy pokazane poniżej. Jeżeli funkcja zwraca wartość > 0, wtedy łańcuch został znaleziony. Możesz równie łatwo zwrócić 1 lub 0 zamiast tego.
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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-11 02:09:50
Bash4 + przykłady. Uwaga: nieużywanie cudzysłowów spowoduje problemy, gdy słowa zawierają spacje itp.. Zawsze cytuję w bash IMO.
Oto kilka przykładów BASH4+:
Przykład 1, zaznaczenie "tak" w łańcuchu znaków (bez rozróżniania wielkości liter):
if [[ "${str,,}" == *"yes"* ]] ;then
Przykład 2, zaznaczenie "tak" w łańcuchu znaków (bez rozróżniania wielkości liter):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
Przykład 3, Zaznacz "tak" w łańcuchu znaków (rozróżnia wielkość liter):
if [[ "${str}" == *"yes"* ]] ;then
Przykład 4, Zaznacz "tak" w łańcuchu znaków (rozróżnia wielkość liter):
if [[ "${str}" =~ "yes" ]] ;then
Przykład 5, dokładne dopasowanie (wielkość liter):
if [[ "${str}" == "yes" ]] ;then
Przykład 6, dokładne dopasowanie (niewrażliwe na wielkość liter):
if [[ "${str,,}" == "yes" ]] ;then
Przykład 7, dokładne dopasowanie:
if [ "$a" = "$b" ] ;then
Smacznego.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 18:54:36