如何在 Bash 中检查字符串是否包含子字符串

How to check if a string contains a substring in Bash

提问人:davidsheldon 提问时间:10/23/2008 最后编辑:Andrzej Sydordavidsheldon 更新时间:8/17/2023 访问量:3021973

问:

我在 Bash 中有一个字符串:

string="My string"

如何测试它是否包含另一个字符串?

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

我的未知操作员在哪里。我是否使用 和 ???echogrep

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

这看起来有点笨拙。

字符串 bash shell 子字符串 sh

评论

4赞 ericson.cepeda 5/5/2015
嗨,如果空字符串是假的,你为什么认为它很笨拙?尽管提出了解决方案,但这是对我有用的唯一方法。
1赞 cifer 3/2/2016
您可以在此处使用该命令expr
9赞 sehe 4/8/2016
这是 posix shell 的一个:stackoverflow.com/questions/2829613/...
2赞 Piotr Henryk Dabrowski 12/1/2021
请在您的示例中使用$haystack成语中的$needle。它更容易阅读和理解。

答:

483赞 Marcus Griep 10/23/2008 #1

我不确定是否使用 if 语句,但您可以使用 case 语句获得类似的效果:

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

评论

106赞 technosaurus 1/5/2014
这可能是最好的解决方案,因为它可以移植到 posix shell。(又名无抨击)
40赞 P.P 12/18/2015
@technosaurus 我发现在一个只有 bash 标签的问题中批评“bashism”是相当奇怪的:)
69赞 Carl Smotricz 6/3/2016
@P.P.这与其说是批评,不如说是更普遍的解决方案优于更有限的解决方案。请考虑一下,多年后,人们(像我一样)会停下来寻找这个答案,并且可能会很高兴找到一个比原始问题更广泛有用的答案。正如他们在开源世界中所说:“选择是好的!
2赞 maxschlepzig 5/1/2017
@technosaurus,FWIW 也适用于一些符合 POSIX 的 sh 版本(例如 在 Solaris 10 上)和 ksh (>= 88)[[ $string == *foo* ]]/usr/xpg4/bin/sh
0赞 t7e 4/26/2023
@maxschlepzig现在很多人都在使用 docker 容器。大多数默认的 docker 映像没有 bash,类似的东西将不起作用。[[ $string == *foo* ]]
4811赞 Adam Bellaire 10/23/2008 #2

如果您使用双括号,您也可以在 case 语句之外使用 Marcus 的答案(* 通配符):

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

请注意,针串中的空格需要放在双引号之间,通配符应该在外面。另请注意,使用的是简单的比较运算符(即 ),而不是正则表达式运算符。*===~

评论

192赞 Quinn Taylor 7/31/2009
另请注意,只需在测试中切换到 != 即可反转比较。谢谢你的回答!
5赞 Jonik 11/16/2010
嗯,有了这个确切的代码,我得到了.知道出了什么问题吗?我在 Ubuntu 上使用 GNU bash 版本 4.1.5(1)。[[: not found
81赞 Dennis Williamson 12/17/2010
@Jonik:您可能缺少 shebang 或将其视为 .请尝试。#!/bin/sh#!/bin/bash
1赞 Hakim 4/21/2023
也许值得一提的是,它不适用于单运算符(双括号可能是通配符的强制性要求)[[[
2赞 t7e 4/26/2023
是的,这个解决方案不是 POSIX。不适用于许多 docker 容器。sh
106赞 ephemient 10/23/2008 #3

公认的答案是最好的,但由于有多种方法可以做到这一点,这里有另一种解决方案:

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

${var/search/replace}是替换为 的第一个实例,如果找到它(它不会改变)。如果您尝试不进行任何替换,并且字符串已更改,则显然已找到。$varsearchreplace$varfoofoo

评论

5赞 TPoschel 10/8/2010
上面的 ephemient 解决方案: > ' if [ “$string” != “${string/foo/}” ];然后回声“It's there!” fi' 在使用 BusyBox 的 shell ash 时很有用。接受的解决方案不适用于 BusyBox,因为某些 bash 的正则表达式未实现。
3赞 nitinr708 8/1/2017
差异的不平等。很奇怪的想法!我喜欢
1赞 venimus 7/13/2019
除非你的字符串是“foo”,否则
2赞 Todd Lewis 3/26/2021
@hanshenrik 您正在与 .您想要的表达式是$XDG_CURRENT_DESKTOP$stringif [ "$XDG_CURRENT_DESKTOP" != "${XDG_CURRENT_DESKTOP/GNOME/}" ]; then echo MATCHES GNOME; fi
1赞 tomo_iris427 10/13/2021
@venimus是的,更好。"x$string" != "x${string/foo/}"
978赞 Matt Tardiff 10/24/2008 #4

如果您更喜欢正则表达式方法:

string='My string';

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

评论

3赞 blast_hardcheese 2/14/2012
必须替换 bash 脚本中的 egrep 正则表达式,这效果很好!
122赞 bukzor 6/6/2013
运算符已在整个字符串中搜索匹配项;这里的 是无关紧要的。此外,引号通常比反斜杠更可取:=~.*[[ $string =~ "My s" ]]
27赞 seanf 5/12/2015
@bukzor Quotes 从 Bash 3.2+ 开始停止工作: tiswww.case.edu/php/chet/bash/FAQ .最好将变量赋值(使用引号),然后进行比较。喜欢这个:E14)re="My s"; if [[ $string =~ $re ]]
65赞 KrisWebDev 1/24/2016
测试它是否不包含字符串:为 true。if [[ ! "abc" =~ "d" ]]
186赞 Mark Baker 10/27/2008 #5

You should remember that shell scripting is less of a language and more of a collection of commands. Instinctively you think that this "language" requires you to follow an with a or a . Both of those are just commands that return an exit status indicating success or failure (just like every other command). For that reason I'd use , and not the command.if[[[grep[

Just do:

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

Now that you are thinking of as testing the exit status of the command that follows it (complete with semi-colon), why not reconsider the source of the string you are testing?if

## 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
#...

The option makes grep not output anything, as we only want the return code. makes the shell expand the next word and use it as the input to the command, a one-line version of the here document (I'm not sure whether this is standard or a Bashism).-q<<<<<

评论

9赞 alex.pilon 10/21/2011
they are called here strings (3.6.7) I believe it is bashism
13赞 larsr 12/19/2011
one can also use Process Substitution if grep -q foo <(echo somefoothing); then
1赞 Bruno Bronosky 3/28/2015
@nyuszika7h alone is pretty portable. The flags are not. If you find yourself thinking about or use echo-e-nprintf
6赞 F. Hauri - Give Up GitHub 4/20/2015
The cost of this is very expensive: doing implie 1 fork and is bashism and implie 2 forks (one for the pipe and the second for running grep -q foo <<<"$mystring"echo $mystring | grep -q foo/path/to/grep)
1赞 tripleee 4/12/2018
@BrunoBronosky without flags might still have unexpected portability problems if the argument string contains backslash sequences. is expected on some platforms to work like on some others. vs echoecho "nope\c"echo -e "nope"printf '%s' "nope"printf '%s\n' 'nope\c'
5赞 Jadu Saikia 12/21/2008 #6

grep -q is useful for this purpose.

The same using :awk

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

Output:

Not Found

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

Output:

Found

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

评论

3赞 alexia 6/12/2014
echo is unportable, you should be using instead. I'm editing the answer because the user doesn't appear to exist anymore.printf '%s' "$string"
20赞 Stefan 2/9/2009 #7

How about this:

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

评论

2赞 2/9/2009
=~ is for regexp matching, hence too powerful for the OP's purpose.
-1赞 andreas 8/28/2010 #8

Try oobash.

It is an OO-style string library for Bash 4. It has support for German umlauts. It is written in Bash.

Many functions are available:

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
zfill

请看 contains 示例:

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

oobash 可在 Sourceforge.net 上使用

11赞 chemila 11/11/2011 #9

一是:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'

评论

3赞 michael 8/10/2013
expr是那些瑞士军刀实用程序之一,一旦你弄清楚了如何去做,通常可以做任何你需要做的事情,但一旦实施,你永远不记得它为什么或如何做它正在做的事情,所以你再也不会碰它,并希望它永远不会停止做它正在做的事情。
0赞 michael 3/5/2014
@AloisMahdal我从来没有投过反对票,我只是假设为什么投反对票。一个警告性的评论。在极少数情况下,当可移植性阻止使用 bash(例如,旧版本之间的行为不一致)、tr(到处不一致)或 sed(有时太慢)时,我确实会使用 。但从个人经验来看,每当重读这些 -isms 时,我都必须回到手册页。所以,我只想评论一下,每一次用法都被评论了......exprexprexpr
2赞 tripleee 2/11/2016
曾经有一段时间,你所拥有的只是原始的 Bourne 外壳。它缺少一些常用的功能,因此实现了 和 等工具来执行它们。在这个时代,通常有更好的工具,其中许多内置于任何现代外壳中。我猜还挂在那里,但似乎没有人失踪.exprtesttestexpr
1赞 Svet 5/4/2021
点赞,因为我需要一些在 Bourne shell 中工作的东西,而其他一切似乎都是特定于 bash 的。
0赞 Nairum 7/15/2022
expr: syntax error: unexpected argument ‘.*.*’ bash: [: -ne: unary operator expected
4赞 Kurt Pfeifle 7/1/2012 #10

我发现经常需要这个功能,所以我在我的 like this 中使用了一个自制的 shell 函数,它允许我根据需要经常重用它,并带有一个易于记忆的名称:.bashrc

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

例如,要测试(比如,abc)是否包含在(比如,123abcABC)中,我只需要运行并检查返回值$string1$string2stringinstring "$string1" "$string2"

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

评论

0赞 elyase 12/12/2012
[[ “$str” == $substr ]] && echo YES ||echo 否
0赞 alexia 6/12/2014
我很确定只有非常旧的 shell 才需要 hack。x
0赞 Mikhail T. 2/24/2021
函数的正确 - 并且可立即识别 - 名称是:-)strstr()
31赞 kevinarpe 12/1/2012 #11

这也有效:

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

阴性测试是:

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

我想这种风格更经典一些——不太依赖于 Bash shell 的功能。

该参数是纯粹的 POSIX 偏执狂,用于防止类似于选项的输入字符串,例如 或 .----abc-a

注意:在紧密循环中,此代码将比使用内部 Bash shell 功能慢得多,因为将创建一个(或两个)单独的进程并通过管道连接。

评论

5赞 michael 8/10/2013
...但 OP 没有说是哪个版本的 bash;例如,较旧的 bash(例如 Solaris 经常拥有的)可能不包含这些较新的 bash 功能。(我在 solaris w/ bash 2.0 上遇到了这个确切的问题(未实现 bash 模式匹配)
2赞 alexia 6/12/2014
echo是不可移植的,您应该改用。printf '%s' "$haystack
2赞 alexia 8/16/2014
不,只是完全避免使用任何内容,但文字文本除外,没有不以 . 开头的转义词它可能适合您,但不可移植。即使是 bash 的行为也会有所不同,具体取决于是否设置了该选项。附言:我忘了在之前的评论中关闭双引号。echo-echoxpg_echo
1赞 alexia 3/17/2015
@kevinarpe我不确定,是否未在 printf 的 POSIX 规范中列出,但您无论如何都应该使用,以避免包含字符时出现问题。--printf '%s' "$anything"$anything%
1赞 alexia 6/17/2016
@kevinarpe 基于此,它可能是。
11赞 Yordan Georgiev 8/26/2013 #12

这个 Stack Overflow 答案是唯一一个捕获空格和破折号字符的答案:

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

评论

3赞 Peter Mortensen 1/1/2020
这是对同一问题的回答。
346赞 F. Hauri - Give Up GitHub 12/9/2013 #13

全面重写 2023-07-03!!

字符串包含:POSIX 兼容性、大小写无关、提示和备注。bash

介绍

之前的答案是基于参数扩展的,但是在与基于案例的解决方案进行比较后,正如Marcus Griep的答案所提出的那样,我不得不承认:案例方法的效率要高得多

简述必不可少

case $string in
    *$substring* )
         do something with "$substring"
         ;;
esac 

As a function:

stringContain() { case $2 in *$1* ) return 0;; *) return 1;; esac ;}

Usage sample

for string in 'echo "My string"'    "Don't miss quotes"    ''; do # 3 strings
    for substr in "'t mis"   'o "My'   "s"   "Y"   ""; do # 5 substrings
        if stringContain "$substr" "$string"; then
            printf 'Match: %-12s %s\n' "'$substr'" "'$string'"
        else
            printf 'No match: %s\n' "'$substr'"
        fi
    done
done
No match: ''t mis'
Match: 'o "My'      'echo "My string"'
Match: 's'          'echo "My string"'
No match: 'Y'
Match: ''           'echo "My string"'
Match: ''t mis'     'Don't miss quotes'
No match: 'o "My'
Match: 's'          'Don't miss quotes'
No match: 'Y'
Match: ''           'Don't miss quotes'
No match: ''t mis'
No match: 'o "My'
No match: 's'
No match: 'Y'
Match: ''           ''

Alternative using parameter expansion

In previous answer I'd proposed:

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

But after doing some comparisons, using , , and , here is my average result:dashbusybox shellbashksh

Comparing time PExp vs Case method under bash    :    634.71%
Comparing time PExp vs Case method under dash    :    878.87%
Comparing time PExp vs Case method under ksh     :    217.95%
Comparing time PExp vs Case method under busybox :    752.42%

Full test script: stringContain-test.sh

case method is at least 2 time quicker than parameter expansion method regardless shell implementation used.

Semantically:

  • case method: in case string match anything (could be nothing), followed by substring, followed by anything. is a single test.
  • parameter expansion: If substring is empty or string where anything followed by substring followed by anything is replaced by nothing is nothing and string do contain something is a complex multiple test after string transformation

From this point of view, this seem easy to understand that case method is more efficient!

Case independent

Under and some other , you could use parameter expansion to quickly transform your string to lower or upper case, by using respectively: and :${var,,}${var^^}

So adding option to function, for case independent, could be done by:-i

stringContain() {
    if [[ $1 == -i ]] ; then
        case ${3,,} in
            *${2,,}*) return 0;;
            *) return 1;;
        esac
    else
        case $2 in
            *$1*) return 0;;
            *) return 1;;
        esac
    fi
}
stringContain hello 'Hello world!' && echo yes || echo no
no
stringContain -i hello 'Hello world!' && echo yes || echo no
yes

评论

1赞 Eero Aaltonen 12/10/2013
This would be even better, if you can figure out some way to put that to a function.
2赞 F. Hauri - Give Up GitHub 5/7/2014
@EeroAaltonen How do you find my (new added) function?
2赞 eggmatters 7/16/2014
I know! find . -name "*" | xargs grep "myfunc" 2> /dev/null
1赞 eggmatters 7/17/2014
@F.Hauri Sorry, was a joke to your comment to EuroAaltonen The find command has absolutely nothing to do with the question posted on this thread.
8赞 Sjlver 10/24/2014
This is wonderful because it's so compatible. One bug, though: It does not work if the haystack string is empty. The correct version would be A final thought: does the empty string contain the empty string? The version above things yes (because of the part).string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; }-o -z "$1"
82赞 Paul Hedderly 8/28/2014 #14

So there are lots of useful solutions to the question - but which is fastest / uses the fewest resources?

Repeated tests using this frame:

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

Replacing TEST each time:

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

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

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

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

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

(doContain was in F. Houri's answer)

And for giggles:

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

So the simple substitution option predictably wins whether in an extended test or a case. The case is portable.

Piping out to 100000 greps is predictably painful! The old rule about using external utilities without need holds true.

评论

8赞 Mad Physicist 7/14/2016
Neat benchmark. Convinced me to use .[[ $b == *$a* ]]
2赞 tripleee 4/12/2018
If I'm reading this correctly, wins with the smallest overall time consumption. You are missing an asterisk after though. I get slightly faster results for than for with the bug corrected, but it could depend on other factors too, of course.case$b in *$a[[ $b == *$a* ]]case
1赞 tripleee 4/12/2018
ideone.com/5roEVt has my experiment with some additional bugs fixed and tests for a different scenario (where the string is actually not present in the longer string). Results are largely similar; is quick and is almost as quick (and pleasantly POSIX-compatible).[[ $b == *$a* ]]case
0赞 r a 2/19/2021
The conditional expression and the case statement are not equivalent in a no-match condition. Swapping and results in exit code 1 for the conditional expression and exit code 0 for the statement. As per : Exit Status: Returns the status of the last command executed. The return status is zero if no pattern is matched, which is probably not the expected behavior. To return 1 in the no match condition, it should be: [[ $b == *$a* ]]case $b in *$a):;;esac $a$b[[casehelp casecase $b in *$a*):;; *) false ;; esac
27赞 Samuel 1/1/2015 #15

As Paul mentioned in his performance comparison:

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

This is POSIX compliant like the 'case "$string" in' the answer provided by Marcus, but it is slightly easier to read than the case statement answer. Also note that this will be much much slower than using a case statement. As Paul pointed out, don't use it in a loop.

评论

1赞 mirekphd 8/15/2023
And it's the only one that actually works in modern GNU bash (5.x)
12赞 Jahid 4/29/2015 #16
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

评论

0赞 nicodjimenez 10/17/2017
I will add that the statement at the end is a nice trick to return 0 exit statuses for these matching commands.echo "Couldn't find
0赞 Jahid 10/17/2017
@nicodjimenez you can not target exit status any more with this solution. Exit status is swallowed up by the status messages ...
1赞 nicodjimenez 10/17/2017
That's exactly what I meant... If you don't have then you will return an error exit status if there is no match, which you might not want if you're running a CI pipeline for example where you want all commands to return non error exit statuses|| echo "Couldn't find"
5赞 ride 3/4/2016 #17

I like sed.

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

Edit, Logic:

  • Use sed to remove instance of substring from string

  • If new string differs from old string, substring exists

4赞 Eduardo Cuomo 11/10/2016 #18

Exact word match:

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

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi
6赞 Leslie Satenstein 1/14/2017 #19

My .bash_profile file and how I used grep:

If the PATH environment variable includes my two directories, don't append them,bin

# .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

评论

0赞 Mohamed Bana 2/7/2017
点赞。当功能更强大的 grep 很可能可用时,为什么要费心去了解 Bash 是如何做到的。还可以通过与模式列表进行匹配来进一步扩展它:.grep -q -E 'pattern1|...|patternN'
2赞 Ethan Post 4/11/2018 #20

我使用这个函数(一个依赖项不包括在内,但很明显)。它通过了如下所示的测试。如果函数返回的值> 0,则找到字符串。你可以很容易地返回 1 或 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
}

评论

0赞 Peter Mortensen 1/1/2020
悬念!什么是依赖关系?
0赞 Ethan Post 1/2/2020
“str_escape_special_characters”功能。它位于 GitHub arcshell_str.sh 文件中。arcshell.io 会带你去那里。
0赞 pkfm 10/4/2020
str_escape_special_characters似乎已经变成了.请参阅 @ ArcLogicSoftware/Arcshellstr_escapearcshell_str.sh
69赞 Mike Q 10/6/2018 #21

Bash 4+ 示例。注意:不使用引号会导致单词包含空格等问题。始终在 Bash、IMO 中引用。

以下是 Bash 4+ 的一些示例:

示例 1,检查字符串中的“yes”(不区分大小写):

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

示例 2,检查字符串中的“yes”(不区分大小写):

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

示例 3,检查字符串中的“yes”(区分大小写):

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

示例 4,检查字符串中的“yes”(区分大小写):

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

示例 5,完全匹配(区分大小写):

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

示例 6,完全匹配(不区分大小写):

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

示例 7,完全匹配:

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

示例 8,通配符匹配 .ext(不区分大小写):

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

示例 9,对区分大小写的字符串使用 grep:

     if echo "SomeString" | grep -q "String"; then

示例 10,在不区分大小写的字符串上使用 grep:

     if echo "SomeString" | grep -iq "string"; then

示例 11,在字符串上使用 grep 不区分大小写,带通配符:

     if echo "SomeString" | grep -iq "Some.*ing"; then

示例 12,使用 doublehash 进行比较(如果变量 empty 可能导致错误正语等)(区分大小写):

     if [[ ! ${str##*$substr*} ]] ;then  #found

享受。

评论

2赞 hey 1/18/2021
啊啊 - 在我发现两个逗号转换为小写后,我才明白它。伟大的解决方案/伟大的清单!${str,,}$str
0赞 Sam Sirry 3/1/2023
现在,如果我正在测试一个变量,该怎么办?有用吗?bash 说道${str}${$MYVAR,,}bad substitution
0赞 Mike Q 3/1/2023
@SamSirry 您的示例中有一个拼写错误,请删除第二个 $。它应该是 ${VAR,,}。请注意,如果这不起作用,那么您有一个旧的 shell,必须使用上面的其他选项之一。
6赞 Alex Skrypnyk 2/2/2019 #22

这里回答的问题的扩展 如何判断一个字符串是否包含POSIX sh中的另一个字符串?

此解决方案适用于特殊字符:

# 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*"

评论

2赞 joeytwiddle 12/12/2019
The test doesn't work here, because will swallow the as an option! A popular fix for that is to use instead.contains "-n" "n"echo -n-nprintf "%s\n" "$string"
1赞 fjarlq 3/31/2023
I have fixed my answer that you linked so that it now works with special characters. As @midnite pointed out, all it needed was doublequotes around the substring when using POSIX substring parameter expansion. I also stole a few of your test cases. Thanks, Alex.
7赞 FifthAxiom 12/4/2019 #23

Since the POSIX/BusyBox question is closed without providing the right answer (IMHO), I'll post an answer here.

The shortest possible answer is:

[ ${_string_##*$_substring_*} ] || echo Substring found!

or

[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Note that the double hash is obligatory with some shells (). Above will evaluate when the substring is not found. It returns no error. When the substring is found the result is empty and it evaluates . This will throw error code 1 since the string is completely substituted (due to ).ash[ stringvalue ][ ]*

The shortest more common syntax:

[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'

or

[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Another one:

[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'

or

[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'

Note the single equal sign!

0赞 BobMonk 2/13/2020 #24
msg="message"

function check {
    echo $msg | egrep [abc] 1> /dev/null

    if [ $? -ne 1 ];
    then 
        echo "found" 
    else 
        echo "not found" 
    fi
}

check

This will find any occurance of a or b or c

6赞 Pipo 3/17/2020 #25

The generic needle haystack example is following with variables

#!/bin/bash

needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
    echo "needle found"
else
    echo "needle NOT found"
fi
5赞 Koichi Nakashima 3/27/2020 #26
case $string in (*foo*)
  # Do stuff
esac

This is the same answer as https://stackoverflow.com/a/229585/11267590. But simple style and also POSIX Compliant.

19赞 Piotr Henryk Dabrowski 12/1/2021 #27

Accepted answer is correct but it is hard to read and understand.
For problems related to searching you should always use the $needle in a $haystack idiom.
Since its suggested edit queue is full, I post this:

haystack='There are needles here.'
if [[ "$haystack" == *"needle"* ]]; then
    echo "It's there!"
fi

评论

0赞 Sam Sirry 3/1/2023
It must be mentioned that this only works under , and when this is used in a script file, it must start with the line bash#!/bin/bash
2赞 Francesco Gasparetto 4/20/2022 #28

You can use a logic && to be more compact

#!/bin/bash

# NO MATCH EXAMPLE
string="test"
[[ "$string" == *"foo"* ]] && {
        echo "YES"
}

# MATCH EXAMPLE
string="tefoost"
[[ "$string" == *"foo"* ]] && {
        echo "YES"
}
0赞 JanB 6/9/2022 #29

使用 jq

string='My long string'
echo $string | jq -Rr 'select(contains("long"))|"It is there"'

jq 中最难的是打印单引号:

echo $string | jq --arg quote "'" -Rr 'select(contains("long"))|"It\($quote)s there"'

仅使用 jq 来检查条件:

if jq -Re 'select(contains("long"))|halt' <<< $string; then
    echo "It's there!"
fi
0赞 t7e 4/26/2023 #30

这是 POSIX 变体,但具有:sed

string="My string"
pattern="string"

if [ "${string}" != "$(printf '%s' "${string}" | sed 's/'"${pattern}"'//g')" ]; then
 echo "It's there!"; 
fi

一些解释:

sed 's/'"${pattern}"'//g'去除 的模式。 因此,它看起来像这样:${string}

if [ "My string" != "My " ];

它们不相等,而是 ,所以这意味着模式就在那里。true

如果使用不同的模式,例如 ,则等式为:pattern="foo"

if [ "My string" != "My string" ];

因为在这种情况下不会剥离任何东西,它会产生.sedfalse

它看起来仍然很笨拙,但此选项适用于许多 shell,例如 dash、zsh,而不仅仅是 bash。