当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何检查字符串是否包含Bash中的子字符串》经验,为你挑选了18个好方法。

我在Bash中有一个字符串:

string="My string"

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

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

??我的未知运营商在哪里?我是否使用echo grep

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

这看起来有点笨拙.



1> Adam Bellair..:

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

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

请注意,针串中的空格需要放在双引号之间,*通配符应该在外面.


另请注意,您可以通过在测试中切换到!=来反转比较.谢谢你的回答!
@Jonik:你可能会错过shebang或者把它作为`#!/ bin/sh`.请尝试`#!/ bin/bash`.
您不需要在[[]]中引用变量.这也可以:[[$ string ==*$ needle*]] && echo found
@Orwellophile**小心!**你只能省略第一个参数中的双引号`[[`.请参见http://ideone.com/ZSy1gZ
在括号和内容之间留一个空格.
我想出了这个问题.如果从另一个脚本调用脚本,请确保使用`bash nameofscript.sh`而不是`sh nameofscript.sh`.
顺便说一句,确保星号不在引号中:`if [["$ args"==*" - l"*]]`
注意!`if [[*"My long"*== $ string]];`不起作用,而`if [[$ string ==*"My long"*]];`有效.有没有人解释这个?
在bash 4.4中这对我不起作用
嗯,有了这个确切的代码,我得到了`[[:not found`.知道什么是错的吗?我在Ubuntu上使用GNU bash,版本4.1.5(1).
我花了很长时间才意识到使用`#!/ bin/bash`,语句的每个元素之间需要空格,例如`if [[$ input_var =="test"]]`
警告:这是一个所谓的*基础*!正如@DennisWilliamson指出的那样,这项工作仅在[tag:bash]下,但不适用于常规的[tag:shell]!(我写了一个[兼容功能](http://stackoverflow.com/a/20460402/1765658),它可以在像busybox这样糟糕的shell下运行
@maxschlepzig你错了:这是*bashisms*!小心你的`/ bin/sh`不是'bash`的链接!对于我自己,我现在只试过"破折号":`破折号:2:[[:未找到`

2> Matt Tardiff..:

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

string='My string';

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


`= ~`运算符已经在整个字符串中搜索匹配项; 这里的`.*`是无关紧要的.另外,引号通常比反斜杠更好:`[[$ string =〜"My s"]]`
测试它是否******包含一个字符串:`if [[!"abc"=〜"d"]]`是真的.
@bukzor报价从Bash 3.2+开始停止工作:http://tiswww.case.edu/php/chet/bash/FAQ`E14)`.最好分配给变量(使用引号),然后进行比较.像这样:`re ="我的s"; if [[$ string =〜$ re]]`
不得不在bash脚本中替换egrep正则表达式,这非常有效!

3> Marcus Griep..:

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

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


这可能是最好的解决方案,因为它可以移植到posix shell.(又名没有bashisms)
@PP对于更普遍的解决方案而不是更有限的解决方案而言,这并不是一种批评.请注意,多年以后,人们(像我一样)会停下来寻找这个答案,并且可能很高兴找到一个比原始问题范围更广泛的答案.正如他们在开源世界中所说:"选择很好!"
@technosaurus我觉得在一个只有bash标签的问题上批评"bashism"是相当奇怪的:)
@ technosaurus,FWIW`[[$ string == * foo *]]`在某些POSIX兼容的sh版本(例如Solaris 10上的`/ usr / xpg4 / bin / sh`)和ksh(> = 88)中也可以使用

4> F. Hauri..:

兼容的答案

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

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

在实践中,这可能会给:

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

这是在bash,dash,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'.

成一个功能

正如@EeroAaltonen所说,这是一个相同的演示版本,在相同的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
}

然后:

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

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

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

功能简单

这是在busybox,dash和当然bash下测试的:

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

这就是所有人!

那么现在:

$ 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

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

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

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

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

使用空字符串:

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


这很棒,因为它非常兼容.但是有一个错误:如果haystack字符串为空,它就不起作用.正确的版本是`string_contains(){[ - z"$ {2 ##*$ 1*}"] && [-n"$ 2"-o -z"$ 1"]; 最后的想法:空字符串是否包含空字符串?上面的版本是肯定的(因为`-o -z"$ 1"`部分).
+1.很好!对我来说,我改变了命令stringContain(){[ - z"$ {1 ##*$ 2*}"] && [-z"$ 2"-o -n"$ 1"]; }; "搜索位置""查找内容".在busybox中工作.上面接受的答案在busybox中不起作用.
@EeroAaltonen你如何找到我的(新添加的)功能?
我知道!找 .-name"*"| xargs grep"myfunc"2>/dev/null

5> Mark Baker..:

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

做就是了:

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

现在您正在考虑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
#...

-q选项使grep不输出任何内容,因为我们只需要返回代码.<<<使shell扩展下一个单词并将其用作命令的输入,这是本<<文档的单行版本(我不确定这是标准还是基础).


如果grep -q foo <(echo somefoothing),也可以使用[Process Substitution](http://www.gnu.org/s/bash/manual/bash.html#Process-Substitution).then`
他们被称为[这里的字符串(3.6.7)](http://www.gnu.org/s/bash/manual/bash.html)我认为它是bashism
这个成本非常昂贵:做`grep -q foo <<<"$ mystring"`implie 1 fork and is*bashism*和`echo $ mystring | grep -q foo` implie 2 forks(一个用于管道,第二个用于运行`/ path/to/grep`)

6> ephemient..:

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

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

${var/search/replace}$var第一个search被替换的实例replace,如果找到它(它没有改变$var).如果你试图替换foo什么,并且字符串已经改变,那么显然foo是找到了.


以上ephemient的解决方案:>`if ["$ string"!="$ {string/foo /}"]; 然后回应"它在那里!" 当使用BusyBox的shell*ash*时,fi`非常有用.已接受的解决方案不适用于BusyBox,因为某些bash的正则表达式未实现.

7> Paul Hedderl..:

所以这个问题有很多有用的解决方案 - 但哪个最快/使用最少的资源?

使用此框架重复测试:

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

每次更换TEST:

[[ $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在F. Houri的回答中)

对于咯咯地笑:

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

因此,无论是在扩展测试还是案例中,简单替代选项都可以获得胜利.外壳是便携式的.

管道输出到100000 greps是可以预料的痛苦!关于无需使用外部实用程序的旧规则是正确的.


整洁的基准。说服我使用`[[$ b == * $ a *]]`。
如果我正确地阅读了此内容,则“ case”以最小的总时间消耗获胜。不过,您在* $ a中的$ b之后缺少星号。我得到的[[[$ b == * $ a *]]`的结果比修正了错误的`case`的结果要快一些,但是,当然,它也可能取决于其他因素。

8> kevinarpe..:

这也有效:

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.

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


......但是OP没有说bash是哪个_version_; 例如,较旧的bash(例如solaris经常有)可能不包括这些较新的bash功能.(我在solaris w/bash 2.0上遇到了这个确切的问题(bash模式匹配未实现))
`echo`是不可移植的,你应该使用`printf'%s'"$ haystack`代替.
不,只是避免`echo`,除了文字文本,没有不以`-`开头的转义.它可能适合你,但它不便携.甚至bash的`echo`也会有不同的表现,这取决于是否设置了`xpg_echo`选项.**PS:**我忘记在之前的评论中关闭双引号.

9> Mike Q..:

Bash4 +示例.注意:当单词包含空格等时,不使用引号会导致问题.总是引用bash IMO.

以下是BASH4 +的一些示例:

例1,检查字符串中的"是"(不区分大小写):

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

例2,检查字符串中的"是"(不区分大小写):

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

例3,检查字符串中的"是"(区分大小写):

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

例4,检查字符串中的"是"(区分大小写):

     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

请享用.



10> 小智..:

这个怎么样:

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



11> Samuel..:

保罗在他的表现比较中提到:

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

这与POSIX兼容,就像Marcus提供的'case'$ string"in'答案一样,但比case语句答案稍微容易阅读.另请注意,这将比使用case语句慢得多,正如Paul指出的那样,不要在循环中使用它.



12> Yordan Georg..:

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

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



13> chemila..:

一个是:

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


`expr`是瑞士军刀实用工具之一,一旦你弄清楚如何做就可以做你需要做的任何事情,但一旦实施,你永远不会记得为什么或如何做它正在做的事情,所以你永远不要再触摸它,并希望它永远不会停止做它正在做的事情.

14> Jahid..:
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"



15> ride..:

我喜欢sed.

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

编辑,逻辑:

使用sed从string中删除子串的实例

如果新字符串与旧字符串不同,则存在子字符串



16> 小智..:

grep -q 对此有用.

同样使用awk:

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

输出:

未找到

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

输出:

发现

原始来源:http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html


`echo`是不可移植的,您应该改用`printf'%s'“ $ string”`。我正在编辑答案,因为该用户似乎不再存在。

17> Kurt Pfeifle..:

我发现经常需要此功能,因此我以这种方式使用自制的shell函数,.bashrc该函数使我可以按需要多次重复使用它,并且名称易于记忆:

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

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

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



18> Leslie Saten..:

我的.bash_profile以及我如何使用grep如果PATH包含我的2个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

推荐阅读
mylvfamily
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有