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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/229551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:19:07  来源:igfitidea点击:

How to check if a string contains a substring in Bash

stringbashshellsubstringsh

提问by davidsheldon

I have a string in Bash:

我在 Bash 中有一个字符串:

string="My string"

How can I test if it contains another string?

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

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

Where ??is my unknown operator. Do I use echo and grep?

??我的未知接线员在哪里。我使用 echo 和grep吗?

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

That looks a bit clumsy.

这看起来有点笨拙。

回答by Adam Bellaire

You can use Marcus's answer (* wildcards)outside a case statement, too, if you use double brackets:

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

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

Note that spaces in the needle string need to be placed between double quotes, and the *wildcards should be outside. Also note that a simple comparison operator is used (i.e. ==), not the regex operator =~.

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

回答by Matt Tardiff

If you prefer the regex approach:

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

string='My string';

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

回答by Marcus Griep

I am not sure about using an if statement, but you can get a similar effect with a case statement:

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

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

回答by F. Hauri

stringContainvariants (compatible or case independent)

stringContain变体(兼容或独立于案例)

As these Stack Overflow answers tell mostly about Bash, I've posted a case independentBash function at the very bottom of this post...

由于这些 Stack Overflow 答案主要是关于Bash,我在这篇文章的最底部发布了一个独立案例的Bash 函数......

Anyway, there is my

反正有我的

Compatible answer

兼容答案

As there are already a lot of answers using Bash-specific features, there is a way working under poorer-featured shells, like BusyBox:

由于已经有很多使用 Bash 特定功能的答案,因此有一种方法可以在功能较差的 shell 下工作,例如BusyBox

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

In practice, this could give:

在实践中,这可以给出:

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

This was tested under Bash, Dash, KornShell(ksh) and ash(BusyBox), and the result is always:

这是在 Bash、DashKornShell( ksh) 和ash(BusyBox) 下测试的,结果总是:

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

Into one function

合一功能

As asked by @EeroAaltonen here is a version of the same demo, tested under the same shells:

正如@EeroAaltonen 所问的,这里是相同演示的一个版本,在相同的 shell 下进行了测试:

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

Then:

然后:

$ 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:you have to escape or double enclose quotes and/or double quotes:

注意:您必须转义或双引号和/或双引号:

$ 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'.

Simple function

简单的功能

This was tested under BusyBox, Dash, and, of course Bash:

这是在 BusyBox、Dash 和 Bash 下测试的:

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

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

... Or if the submitted string could be empty, as pointed out by @Sjlver, the function would become:

...或者如果提交的字符串可能为空,如@Sjlver 所指出的,该函数将变为:

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

or as suggested by Adrian Günter's comment, avoiding -oswitches:

或者按照Adrian Günter 的评论的建议,避免-o切换:

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

Final (simple) function:

最终(简单)函数:

And inverting the tests to make them potentially quicker:

并反转测试以使其可能更快:

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

With empty strings:

使用空字符串:

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

Case independent (Bash only!)

大小写无关(仅限 Bash!)

For testing strings without care of case, simply convert each string to lower case:

要测试不区分大小写的字符串,只需将每个字符串转换为小写:

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

Check:

查看:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

回答by Mark Baker

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 ifwith 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 grep, and not the [command.

您应该记住,shell 脚本与其说是一种语言,不如说是一组命令。你本能地认为这种“语言”要求你跟在ifa[或 a 后面[[。这两个都只是返回指示成功或失败的退出状态的命令(就像所有其他命令一样)。出于这个原因,我会使用grep, 而不是[命令。

Just do:

做就是了:

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

Now that you are thinking of ifas 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 "")"
if grep -q "tar archive" <<<"$filetype"; then
#...

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

The -qoption 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选项使 grep 不输出任何内容,因为我们只想要返回码。<<<使 shell 扩展下一个单词并将其用作命令的输入,<<here 文档的单行版本(我不确定这是标准还是 Bashism)。

回答by ephemient

The accepted answer is best, but since there's more than one way to do it, here's another solution:

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

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

${var/search/replace}is $varwith the first instance of searchreplaced by replace, if it is found (it doesn't change $var). If you try to replace fooby nothing, and the string has changed, then obviously foowas found.

${var/search/replace}$varsearch替换为的第一个实例replace,如果找到(它不会改变$var)。如果您尝试用空替换foo,并且字符串已更改,则显然foo已找到。

回答by Paul Hedderly

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:

每次更换 TEST:

[[ $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)

(doContain 在 F. Houri 的回答中)

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.

输出到 100000 grep 是可以预见的痛苦!关于无需使用外部实用程序的旧规则适用。

回答by kevinarpe

This also works:

这也有效:

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

And the negative test is:

阴性测试是:

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

I suppose this style is a bit more classic -- less dependent upon features of Bash shell.

我想这种风格更经典一些——较少依赖 Bash shell 的特性。

The --argument is pure POSIX paranoia, used to protected against input strings similar to options, such as --abcor -a.

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

Note: In a tight loop this code will be muchslower than using internal Bash shell features, as one (or two) separate processes will be created and connected via pipes.

注意:在一个紧凑的循环这个代码将是多少比使用内部击壳特征慢,作为一个(或两个)独立的过程将被创建并经由配管连接。

回答by Mike Q

Bash 4+ examples. Note: not using quotes will cause issues when words contain spaces, etc. Always quote in Bash, IMO.

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

Here are some examples Bash 4+:

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

Example 1, check for 'yes' in string (case insensitive):

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

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

Example 2, check for 'yes' in string (case insensitive):

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

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

Example 3, check for 'yes' in string (case sensitive):

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

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

Example 4, check for 'yes' in string (case sensitive):

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

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

Example 5, exact match (case sensitive):

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

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

Example 6, exact match (case insensitive):

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

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

Example 7, exact match:

例7,完全匹配:

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

Example 8, wildcard match .ext (case insensitive):

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

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

Enjoy.

享受。

回答by Mike Q

How about this:

这个怎么样:

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