我在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
这看起来有点笨拙。
我在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
这看起来有点笨拙。
当前回答
公认的答案是正确的,但很难阅读和理解。对于与搜索相关的问题,应始终使用$needle in a$haystack习语。由于建议的编辑队列已满,我发布了以下内容:
haystack='There are needles here.'
if [[ "$haystack" == *"needle"* ]]; then
echo "It's there!"
fi
其他回答
字符串包含变量(兼容或不区分大小写)
由于这些Stack Overflow的答案主要讲述了Bash,我在这篇文章的底部发布了一个独立于大小写的Bash函数。。。
总之,有我的
兼容答案
由于已经有很多使用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、KornShell(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所问,这里是相同演示的一个版本,在相同的外壳下测试:
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" ]; }
或者正如Adrian Günter的评论所建议的,避免使用-o开关:
stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ];};}
最终(简单)功能:
并反转测试以使其可能更快:
stringContain() { [ -z "$1" ] || { [ -z "${2##*$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
独立于大小写(仅限Bash!)
对于不区分大小写的字符串测试,只需将每个字符串转换为小写:
stringContain() {
local _lc=${2,,}
[ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;}
检查:
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
公认的答案是最好的,但由于有不止一种方法可以做到这一点,这里有另一种解决方案:
if [ "$string" != "${string/foo/}" ]; then
echo "It's there!"
fi
${var/search/replace}是$var,如果找到了第一个搜索实例,则将其替换为replace(它不会更改$var)。如果您试图将foo替换为空,并且字符串发生了更改,那么很明显找到了foo。
您应该记住,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文档的一行版本(我不确定这是标准还是巴什主义)。
使用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
我使用这个函数(一个不包括但很明显的依赖项)。它通过了以下测试。如果函数返回值>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
}