首页 文章

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

提问于
浏览
1889

我在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

这看起来有点笨拙 .

21 回答

  • 2

    这个怎么样:

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

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

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

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

    使用此框架重复测试:

    /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是可以预料的痛苦!关于无需使用外部实用程序的旧规则是正确的 .

  • 76

    我的.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
    
  • 10

    一个是:

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

    我经常发现需要这个功能,所以我在我的_79945中使用了一个自制的shell函数,这样我就可以根据需要重复使用它,并且有一个易记的名字:

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

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

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

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

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

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

  • 24

    您应该记住,shell脚本不是一种语言,而是一组命令 . 你本能地认为这个"language"要求你跟 if[[[ . 这两个只是返回退出状态的命令,指示成功或失败(就像所有其他命令一样) . 出于这个原因,我使用 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扩展下一个单词并将其用作命令的输入,这是 << here文档的单行版本(我不确定这是标准还是基础) .

  • 411

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

    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所指出的,不要在循环中使用它 .

  • 254

    This Stack Overflow answer是唯一一个捕获空间和破折号的人:

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

    我使用这个函数(一个依赖项不包括但很明显) . 它通过了下面显示的测试 . 如果函数返回值> 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
    }
    
  • 2693

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

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

    兼容的答案

    由于已经有很多使用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
    

    这是在bashdashkshash(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'.
    

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

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

    简单的功能

    这是在busyboxdash下测试的,当然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" ]; }
    

    或者Adrian Günter's comment建议,避免 -o 开关:

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

    使用空字符串:

    $ if stringContain '' ''; then echo yes; else echo no; fi
    yes
    $ if stringContain 'o "M' ''; then echo yes; else echo no; fi
    no
    
  • 1
    [[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
    
  • 4

    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
    

    请享用 .

  • 3

    你可以在外面使用Marcus's answer (* wildcards)一个case语句,如果你使用双括号:

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

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

  • 8

    确切的单词匹配:

    string='My long string'
    exactSearch='long'
    
    if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
      then
        echo "It's there"
      fi
    
  • 2

    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

  • 35

    我喜欢sed .

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

    编辑,逻辑:

    • 使用sed从字符串中删除子字符串的实例

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

  • 122

    尝试oobash它是bash 4的OO风格的字符串库 . 它支持德语变音符号 . 它是用bash编写的 . 许多功能可用: -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 .

    查看包含示例:

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

    oobash is available at Sourceforge.net .

  • 12

    这也有效:

    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功能慢得多,因为将创建一个(或两个)单独的进程并通过管道连接 .

相关问题