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

3490

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

看起来有点笨拙。


4
嗨,如果空字符串是假的,为什么你认为它笨拙?尽管有提出的解决方案,但这是我唯一有效的方法。 - ericson.cepeda
1
你可以在这里使用 expr 命令。 - cifer
9
这是一个适用于posix shell的例子:https://dev59.com/yXE85IYBdhLWcg3wVR6g - sehe
2
请在您的示例中使用“$haystack中的*$needle*”习语。这样更容易阅读和理解。 - Piotr Henryk Dabrowski
30个回答

5

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


3
“echo”是不可移植的,你应该使用“printf '%s' "$string"”代替。我正在编辑答案,因为该用户似乎不存在了。 - alexia
echo 在哪些方面不具备可移植性,@nyuszika7h? - starbeamrainbowlabs

4

我经常需要这种功能,所以我在我的.bashrc中使用了一个自制的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

[[ "$str" == $substr ]] && echo YES || echo NO - elyase
我非常确定 x hack 仅适用于非常老的 shell。 - alexia
您的函数适当且易于识别的名称应为strstr() :-) - Mikhail T.
@MikhailT.:随意处理这个问题,你喜欢怎么做就怎么做... :-) - Kurt Pfeifle

4

3

精确词匹配:

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

悬念重重!这个依赖是什么? - Peter Mortensen
“str_escape_special_characters”函数。它在GitHub的arcshell_str.sh文件中。访问arcshell.io即可找到。 - Ethan Post
“str_escape_special_characters” 似乎已经变成了 “str_escape”。请查看 arclogicsoftware/arcshell 中的 arcshell_str.sh - pkfm

2

您可以使用逻辑运算符&&来使代码更加简洁。

#!/bin/bash

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

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

0
尝试使用oobash。
这是一个适用于Bash 4的面向对象风格的字符串库。它支持德语umlauts。它是用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 可在 Sourceforge.net 上获得


0
msg="message"

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

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

check

这将查找任何出现的a或b或c


0

这里是 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" ];

由于 sed 在这种情况下不会剥离任何内容,因此它将产生 false

虽然看起来有些笨拙,但这个选项在许多 shell 中都可以使用,如 dash、zsh,而不仅仅是 bash。


-1

使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接