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

这看起来有点笨拙。


当前回答

通用的大海捞针示例下面是变量

#!/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

其他回答

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

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

${var/search/replace}是$var,如果找到了第一个搜索实例,则将其替换为replace(它不会更改$var)。如果您试图将foo替换为空,并且字符串发生了更改,那么很明显找到了foo。

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

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

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

我使用这个函数(一个不包括但很明显的依赖项)。它通过了以下测试。如果函数返回值>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
}
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

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

只要做到:

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

既然您正在考虑如果测试它后面的命令的退出状态(用分号完成),为什么不重新考虑您正在测试的字符串的源代码?

## 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文档的一行版本(我不确定这是标准还是巴什主义)。