我在bash中有一个字符串:
如何测试它是否包含另一个字符串?
1 2 3
| if [ $string ?? 'foo' ]; then
echo"It's there!"
fi |
其中??是我不认识的接线员。我用echo和grep吗?
1 2 3
| if echo"$string" | grep 'foo'; then
echo"It's there!"
fi |
看起来有点笨拙。
- 嗨,如果空字符串是假的,为什么你认为它笨拙?这是唯一对我有效的方法,尽管提出了解决方案。
- 您可以在这里使用expr命令
- 这是一个用于posix shells的命令:stackoverflow.com/questions/2829613/…
如果使用双括号,也可以在case语句之外使用marcus的答案(*widcards):
1 2 3 4
| string='My long string'
if [[ $string == *"My long"* ]]; then
echo"It's there!"
fi |
注意,针串中的空格需要放在双引号之间,并且*通配符应该在外部。
- 还要注意,您可以通过切换到来反转比较!=在测试中。谢谢你的回答!
- 嗯,有了这个确切的代码,我得到了[[: not found。知道怎么了吗?我在Ubuntu上使用的是GNUBash,版本4.1.5(1)。
- @乔尼克:你可能错过了"舍邦"号,或者叫它"以东十一号"。改为试试#!/bin/bash。
- +你的答案是1。谢谢。我在看一些使用这种语法的代码。虽然我现在猜到了我的意图,但我得到了证实。尝试了一段时间的bash脚本指南和google,但直到我看到你的答案才找到我想要的。你能给这样的字符串和通配符匹配的使用提供一个链接吗?谢谢!!
- @丹尼斯威廉姆森,我和约尼克有同样的问题,但我在顶部有正确的#!/bin/bash。还有什么可能导致这个问题?
- 我解决了这个问题。如果从另一个脚本调用脚本,请确保使用的是bash nameofscript.sh,而不是sh nameofscript.sh。
- 没有成功。这句话怎么了?if [["Oh My God" == *My*]]; then echo Yes! ; else echo no.. ; fi返回号,在bash/ubuntu 12.10中。
- 在括号和内容之间留一个空格。
- 它能用在SH外壳上吗?
- 您不需要在[[]]内引用变量。这也同样有效:[$string==$needle]]&;echo found
- @利莫瓦拉看看我的答案
- +1到原始答案。但编辑最好是主观的,最坏是不准确的(这里不需要引用$string,尽管这样做可能是一个很好的实践),而且显然应该回滚。
- 当我有冒号时,这似乎不起作用:""在字符串中,如果[[$string==my:test]]
- 也许是空间,而不是结肠……
- 如何检查字符串是否包含*?
- @小心点!您只能在[[的第一个参数中省略双引号。参见ideone.com/zsy1gz
- @nyuszika7h-真是一团糟:)我会使用一个正则表达式,在bash4中无论如何都不能引用它。
- 顺便说一下,确保星号没有在引号中:if [[" $args" == *" -l"* ]]。
- 我花了很长时间才意识到,使用#!/bin/bash时,语句的每个元素之间都需要空格,例如if [[ $input_var =="test" ]]。
- @DSS提到这是空间,只是想补充一句,你需要逃离它:if [[ $string == *My\ String* ]]。
- 我使用上面的方法,只是有一点不同,我在比较中使用了字符串和子字符串切换的位置,但不适用于我,让我苦苦挣扎了一段时间。有人知道为什么吗?
- 警告:这是所谓的害羞!正如@denniswilliamson所指出的,这只在bash下工作,而不是在常规shell下工作!(我写了一个兼容的函数,可以在像BusyBox这样的糟糕外壳下工作)
- @霍里,这不是一种羞怯。它还与posix sh和ksh一起工作。
- @vasyanovikov,"分词和路径名扩展不在[[和]]之间的单词上执行"(bash(1))。
- @Maxschlepzig右。我在写评论的时候不知道。将在几个小时内删除旧评论和此评论。
- @你错了,这是巴什主义!注意你的/bin/sh不是bash的链接!就我自己而言,我刚刚试过用dash:dash: 2: [[: not found
- @f.hauri,posix 2008将[[列为未指定的保留字。但是:在Solaris10(一个标准兼容的shell)下,ksh 88和/usr/xpg4/bin/sh都理解[[。因此,这不是一种害羞。
- 我注意到,如果在包含文件'readme.linux'的目录中运行这个if [[ $string == *"linux"* ]]; then命令,那么*"linux"*将扩展到README.linux,也就是说*将是全局的,因此匹配将失败。
- 注意!if [[ *"My long"* == $string ]];不起作用,而if [[ $string == *"My long"* ]];起作用。有人能解释吗?
- @我的测试没有在bash下复制sdaau。没有发生全局链接。bash信息页实际上清楚地表明:"单词拆分和文件名扩展不会在"[["和"]]"之间的单词上执行。"
- @bash信息页上的fredrickgauss说:"当'=='和'!使用='运算符时,运算符右侧的字符串被视为模式,并根据*注意模式匹配::中描述的规则进行匹配。如果启用了shell选项"nocasemach"(请参见*中的"shott"说明,请注意shott builtin::),则不考虑字母字符的大小写,执行匹配。如果字符串匹配("==")或不匹配("!"),则返回值为0!=')模式,否则为1。模式的任何部分都可以被引用以强制将其作为字符串进行匹配。"
- 为什么不使用==而不是=?
- 什么在bash中有效。
- 我想说巴什的语法更离奇和挑剔,因为我更清楚…
如果您喜欢regex方法:
1 2 3 4 5 6
| string='My string';
if [[ $string =~ .*My.* ]]
then
echo"It's there!"
fi |
- 必须在bash脚本中替换一个egrep regex,这非常有效!
- 如果我需要空间,它不起作用,怎么办?
- 如果您需要一个空格,请用反斜杠将其转义:[[ $string =~ My\ s ]]。
- =~操作符已经在整个字符串中搜索匹配项;这里的.*是无关的。此外,报价通常比反斜杠更可取:[[ $string =~"My s" ]]。
- @Bukzor Quotes从bash 3.2+起停止在这里工作:tiswww.case.edu/php/chet/bash/faq E14)。最好给变量赋值(使用引号),然后进行比较。像这样:re="My s"; if [[ $string =~ $re ]]。
- 测试它是否不包含字符串:if [[ !"abc" =~"d" ]]为真。
- 请注意,测试发生的顺序很重要。以下代码行的输出将向前2。number=2; if [["1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* ="1, 2, 4, 5" ]]; then echo backwards $number; fi;
我不确定是否使用if语句,但您可以使用case语句获得类似的效果:
1 2 3 4 5
| case"$string" in
*foo*)
# Do stuff
;;
esac |
- 这可能是最好的解决方案,因为它可以移植到POSIX shell。(A.K.A.不要刻薄)
- @Technosaurus我觉得在一个只有bash标签的问题中批评"bashism"是很奇怪的。
- @与其说是批评,不如说是更普遍的解决方案,而不是更有限的解决方案。请考虑,几年后,像我这样的人会过来寻找这个答案,并且可能会很高兴找到一个比原始问题更广泛范围内有用的答案。正如他们在开源世界中所说:"选择是好的!"
- @Technosaurus、fwiw-[[ $string == *foo* ]]也适用于某些符合POSIX的sh版本(例如Solaris 10上的/usr/xpg4/bin/sh和ksh(>=88)。
- @麦克斯勒普兹…如果$ifs中有空格、换行符、制表符或用户定义的分隔符等字符,则不是这样…但案例陈述不需要WIERD混合报价,也不需要推送和弹出IFS。
- @Technosaurus,你的意思是因为分词?对于[[,没有分词(例如ksh(1))。这个示例string="hello foo world"; [[ $string == *foo* ]] && echo true按预期为我工作。即使是Ksh 88。是的,在具有默认IFS值(即空格+换行符+制表符)的新shell中。
- @那么,MaxSchlepzig不符合POSIX。ksh显然是korn shell,而不是posix sh;而solaris 10 xpg sh绝对不是posix。
- @triplee,没有人声称ksh是posix sh,而您对xpg4的看法是错误的:"posix.1-1990、posix.2-1992和posix.2a-1992的超集包含了xpg3'xpg4(5)对posix标准的扩展。"您还可以问问自己,Sun以前使用什么sh版本获得POSIX兼容认证。
- 然后,同样的逻辑bash是posix。简单地说,这是一些POSIX shell中的一个特性是误导性的;它绝对是一个非POSIX特性,因此,不管这些shell是否是POSIX,都有点离题。正如您所说,shell包含POSIX之外的扩展。
- 不过,你能在makefile配方中使用这个吗?
- busybox ash不处理[[中的星号…箱子开关工作了!
兼容答案
由于已经有很多使用bash特定特性的答案,所以有一种方法可以在功能较差的shell下工作,比如busybox:
1
| [ -z"${string##*$reqsubstr*}" ] |
实际上,这可能会给:
1 2 3 4 5 6 7 8
| 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)下测试的,结果始终是:
1 2 3
| String 'echo"My string"' contain substring: 'o"M'.
String 'echo"My string"' don't contain substring: 'alt'.
String 'echo"My string"' contain substring: 'str'. |
变成一个函数
正如@eeroaltonen所要求的,这里有一个相同演示的版本,在相同的shell下测试:
1 2 3 4 5 6 7 8 9 10
| 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
} |
然后:
1 2 3 4 5
| $ 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'. |
注意:您必须转义或双圈引号和/或双引号:
1 2 3 4 5
| $ 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下测试的:
1
| stringContain() { [ -z"${2##*$1*}" ]; } |
全是伙计们!
那么现在:
1 2 3 4
| $ 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所指出的那样,函数将变为:
1
| stringContain() { [ -z"${2##*$1*}" ] && [ -z"$1" -o -n"$2" ]; } |
或者按照Adrian G护nter的建议,避免-o开关:
1
| stringContain() { [ -z"${2##*$1*}" ] && { [ -z"$1" ] || [ -n"$2" ] ;} ; } |
使用空字符串:
1 2 3 4
| $ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o"M' ''; then echo yes; else echo no; fi
no |
- 如果你能找到一些方法把它放到一个函数中,这会更好。
- @如何找到我的(新添加的)函数?
- 我知道!找到。-名称"*"xargs grep"myfunc"2>/dev/null
- @eggmates问题代表包含字符串的字符串(而不是包含字符串的文件)。
- @抱歉,你对Euroaaltonen的评论是开玩笑的。find命令与这个线程上发布的问题完全无关。
- $F.Hauri这是我一直在想和希望的。我唯一能做的改变就是改名字。我建议使用"stringcontain",因为至少支持整数。
- 这太棒了,因为它是如此兼容。不过,有一个错误:如果干草堆字符串是空的,它就不起作用。正确的版本是string_contains() { [ -z"${2##*$1*}" ] && [ -n"$2" -o -z"$1" ]; }最后一个想法:空字符串包含空字符串吗?上面的版本是的(因为-o -z"$1"部分)。
- + 1。很好!对于我来说,我更改了order stringcontain()[-z"$1*$2*"]&;&;[-z"$2"-o-n"$1"];"search where""find what"。在Busybox工作。上面接受的答案不适用于BusyBox。
- 类似地,如果[-z$string%%*$subreqstr*];那么echo there;否则echo not there;fi也会工作。
- @是的,这是技术上相同的思维方式,但在实践中可能会有一些不同…我会让你尝试在数千个测试中测试这个问题,看看bash在某种程度上是否比另一种更糟…;-)
- 特殊情况:要搜索的字符串是每行中的第一个词(processor在/proc/cpuinfo中),从命令行中如何获得Linux中的CPU/内核数量,请看这个答案?!
- -a和-o对[的扩展并不完全可移植,因为posix只向四个操作员指定行为。[ -n"$2" ] && [ -z"${2##*$1*}" ] || [ -z"$1" ]是可移植的,并且遵循其他语言的实现行为,尽管我认为切换参数会更清楚(指针前的haystack)。
- @adriang&252;nter as [是一个命令,&&是两个命令之间的分隔,[ -z"$1" -o -n"$2" ]只需考虑,不超过四个运算符(事实上,两个运算符如-n和-z使用隐式运算符)。
- @F.Hauri I懒惰地将两个操作符(-a、-o、-n、-z…)和一级/操作数($1、$2…)都称为[(或者更好的是,参数)的操作符(又称test)。要点是,[ -z"$1" -o -n"$2" ]向[传递了五个参数,这些参数未指明,因此不可靠,不可移植。参见:unix.stackexchange.com/a/57843/83127和pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html >4 arguments: The results are unspecified.。
- @阿德里安&252;中心。哼。。布尔值翻译注意:a & ( b | c )与c & b | a不一样!
- @Adriang&252;输入答案已编辑。
- 我相信,即使是busybox也有case。
- @f.hauri我更改了这里的顺序以进一步优化,但是[ -z"$1" ] || [ -n"$2" ] && [ -z"${2##*$1*}" ]和[ -z"${2##*$1*}" ] && { [ -z"$1" ] || [ -n"$2" ] }在功能上是等效的,只是您的版本效率较低。考虑:如果指针/搜索子字符串$1为空(""),则根本不需要测试[ -z"${2##*$1*}" ],因为每个字符串(包括空字符串!)包含""。如果$1是空字符串,strContain应始终返回success(0)。如果您并行测试我们的版本,您应该发现它们在功能上是等效的。
- 它真的是一个更差的外壳吗?它可能更有限,但它是静态连接的,不是吗?这对系统恢复(某些错误或错误)和其他类似的事情很有帮助。也许在这种情况下,没有必要拥有这种功能,但你永远不会知道。这真的是对其他答案的补充!
- 如果有东西是bash、ksh或香草shell兼容的话,那就好了。
您应该记住,shell脚本不是一种语言,而是一组命令。你本能地认为这种"语言"要求你跟随一个if和一个[或一个[[。这两个命令都只是返回指示成功或失败的退出状态的命令(就像其他所有命令一样)。因此,我会使用grep,而不是[命令。
只做:
1 2 3
| if grep -q foo <<<"$string"; then
echo"It's there"
fi |
现在,您考虑将if作为测试它后面的命令(用分号完成)的退出状态。为什么不重新考虑正在测试的字符串的来源?
1 2 3 4 5 6 7 8
| ## 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扩展下一个单词,并将其用作命令的输入,这是<<的单行版本,这里是文档(我不确定这是标准的还是bashim的)。
- 他们在这里被称为弦乐(3.6.7),我相信这是巴什主义。
- 也可以使用工艺替代物if grep -q foo <(echo somefoothing); then。
- 显然是一种羞怯。
- 注意,echo是不可移植的,如果您要传递一个变量,请使用printf '%s'"$string。
- @仅Nyuszika7h-echo一个非常便携。旗子不是。如果你发现自己在想-e或-n,使用printf。
- 这样做的成本非常昂贵:做grep -q foo <<<"$mystring"表示1叉,是bashism,echo $mystring | grep -q foo表示2叉(一个用于管道,另一个用于运行/path/to/grep)。
- 我们对"成本"和"管理费用"的看法随着我们出生的十年而产生了偏差。我很久以前就参加过"内置测试"V"执行grep"战争,但现在这种战争只不过是学究式的棋盘游戏。你的40亿个硅晶体管只是坐在那里乞求做些什么(最有可能的是电池电流泄漏)。帐篷里的长杆是正确的。P.S.我当然同意你的意见:)
- "shell脚本不是一种语言,而是一组命令",这一评论对于旧的shell和(在较小程度上)符合POSIX的shell而言,比对于更现代的shell(如bash和zsh)更为正确,后者越来越多地包含了以前委托给外部命令的功能。
- @尼尔,我们关于效率不相关的观点被一个表演道歉者后现代主义的叙述所扭曲。只有在耗电的CPU上,不需要任何类似并发的东西,而忽略了事实,这只是一种不便。今天的现代办公室需要并发性,大约99年的规模称为互联网规模。手机大小的通用计算是一个标准,而不是一个例外。因此,注意到实现效率不应该要求神圣的Ruby爱好者们抹平。
- @如果参数字符串包含反斜杠序列,则不带标志的brunobronosky echo可能仍然存在意外的可移植性问题。在某些平台上,预计echo"nope\c"可以像在某些平台上的echo -e"nope"一样工作。printf '%s'"nope"对printf '%s
' 'nope\c'的比较
- @Techzilla记住,我们正在讨论一个bash脚本。没有人会为性能关键的代码编写bash脚本。
- @A提供的经济现实是,通常您需要一个即时的解决方案,而实施选择常常决定"足够好"和"成为性能问题"之间的区别。我们需要检查一下门口的意识形态,没有一个通用的解决方案是不考虑上下文的,而速记答案只会有助于不理解你工作的上下文。
- @ahoffer,性能关键的问题与上下文无关,因为它永远不会是一个问题,而什么才是关键的问题取决于问题的范围和解决方案。在bash中,没有人应该谈论优化紧密的内部循环,他们应该谈论最佳实践。然而,他们也应该讨论并发性,我的观点是非常正确的,大多数人认为这两者是一个,因为经历了蜗牛的结果。知道问题的来龙去脉,回答恰当的来龙去脉,不要重复鼻孔。
- …shell脚本不是一种正确的语言脚本语言。名字说明一切。…命令集合。与…指令相比?没什么区别。本能地,你认为这种"语言"要求你用一个[或一个]来跟随一个if。也许你会,但不是所有人。作为一个程序员(我不认为脚本是编程),我当然不会。…返回一个指示成功或失败的退出状态(就像其他命令一样)。相对于表达式的值?因为这个原因,我会使用grep,而不是[命令]。有时会超过有效的是。
- 根据保罗·海德里的回答,这种方法是最慢的。即使我有更多的CPU,我也不想让它头疼,因为当我的其他应用程序需要系统资源时,这种缓慢可能会使它的丑陋的头部升高。
公认的答案是最好的,但由于有多种方法可以做到这一点,下面是另一种解决方案:
1 2 3
| if ["$string" !="${string/foo/}" ]; then
echo"It's there!"
fi |
${var/search/replace}是$var,如果发现(不改变$var的话,用replace代替search。如果你试图用任何东西替换foo,而字符串已经改变,那么很明显,foo被找到了。
- 上面的ephemient解决方案:>`if["$string"!="$字符串/foo/"];然后回音"它在那儿!"使用busybox的shell ash时fi'非常有用。接受的解决方案不适用于BusyBox,因为一些bash的正则表达式没有实现。
- 差异的不平等。很奇怪的想法!我喜欢它
所以有很多有用的解决方案来解决这个问题——但是哪一个最快/使用最少的资源?
使用此框架的重复测试:
1
| /usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done' |
每次更换测试:
1 2 3 4 5 6 7 8 9
| [[ $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 |
(多康坦在F·胡里的回答中)
对于咯咯笑:
1
| echo $b|grep -q $a 12.68user 30.86system 3:42.40elapsed 19%CPU !ouch! |
因此,无论是在扩展测试中还是在案例中,简单的替换选项都是可以预见的。这个箱子是便携式的。
达到100000个greps是可以预见的痛苦!关于无需使用外部实用程序的旧规则是正确的。
- 整洁的基准。说服我使用[[ $b == *$a* ]]。
- 如果我读得对的话,case以最小的总时间消耗获胜。不过,在$b in *$a后面缺少一个星号。我得到的[[ $b == *$a* ]]的结果比case的稍快,修正了错误,但它也可以依赖于其他因素。
- ideone.com/5roevt已经修复了一些额外的错误,并针对不同的场景进行了测试(其中字符串实际上并不存在于较长的字符串中)。结果基本相似;[[ $b == *$a* ]]很快,case也很快(并且与posix兼容)。
这也适用于:
1 2 3 4
| if printf -- '%s'"$haystack" | egrep -q --"$needle"
then
printf"Found needle in haystack"
fi |
阴性试验为:
1 2 3 4
| if ! printf -- '%s'"$haystack" | egrep -q --"$needle"
then
echo"Did not find needle in haystack"
fi |
我认为这种风格更经典一点——不太依赖于bash shell的特性。
--参数是纯posix偏执狂,用于保护输入字符串不受与选项类似的影响,如--abc或-a。
注意:在一个紧凑的循环中,此代码将比使用内部bash shell特性慢得多,因为将创建一个(或两个)单独的进程并通过管道进行连接。
- 这首歌明显有巴什的标签。
- …但是操作程序没有说明bash的哪个版本;例如,较旧的bash(例如Solaris经常使用)可能不包括这些较新的bash功能。(我在Solaris w/bash 2.0上遇到了这个确切的问题(没有实现bash模式匹配)
- echo是不可移植的,您应该改为使用printf '%s'"$haystack。
- @尼乌斯齐卡7H:我不在,埃多克斯1〔0〕是不受欢迎的。江户十一〔十四〕行吗?
- 不,只需完全避免echo,除了没有转义的文字,而不是以-开头的文字。它可能对你有用,但不便于携带。即使是bash的echo也会根据是否设置了xpg_echo选项而有所不同。附言:我之前的评论中忘记了结束双引号。
- @你知道printf -- 是便携式的还是只有printf 型的?出于习惯,我用printf -- 来保证安全。
- @kevinarpe我不确定,--在printf的posix规范中没有列出,但是无论如何,如果$anything包含%字符,应该使用printf '%s'"$anything"来避免出现问题。
- @Nyuszika7h:谢谢您的详细回复,包括posix规范链接。
- @Nyuszika7h:关于对--的支持,我发现getopt()的这个posix规范:pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.ht&zwnj;&8203;ml。您认为假设printf是posix定义的/兼容的,那么--也会得到支持是安全的吗?
- @基于这一点,可能是基维纳普。
这个怎么样?
1 2 3 4 5 6
| text=" <tag>bmnmn</tag> "
if [["$text" =~"<tag>" ]]; then
echo"matched"
else
echo"not matched"
fi |
- =~用于regexp匹配,因此对于op的目的来说太强大了。
bash4+示例。注意:不使用引号会导致单词包含空格等问题。总是引用bash imo的话。
下面是一些示例bash4+:
示例1,检查字符串中的"是"(不区分大小写):
1
| if [["${str,,}" == *"yes"* ]] ;then |
示例2,检查字符串中的"是"(不区分大小写):
1
| if [["$(echo"$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then |
示例3,检查字符串中的"是"(区分大小写):
1
| if [["${str}" == *"yes"* ]] ;then |
示例4,检查字符串中的"是"(区分大小写):
1
| if [["${str}" =~"yes" ]] ;then |
示例5,完全匹配(区分大小写):
1
| if [["${str}" =="yes" ]] ;then |
示例6,完全匹配(不区分大小写):
1
| if [["${str,,}" =="yes" ]] ;then |
例7,完全匹配:
示例8,通配符match.ext(不区分大小写):
1
| if echo"$a" | egrep -iq"\.(mp[3-4]|txt|css|jpg|png)" ; then |
享受。
正如保罗在他的业绩比较中提到的:
1 2 3 4 5
| if echo"abcdefg" | grep -q"bcdef"; then
echo"String contains is true."
else
echo"String contains is not true."
fi |
这与Marcus提供的'case"$string"答案类似,是POSIX兼容的,但比case-statement答案更容易阅读。还要注意,这将比使用case语句慢得多,正如Paul指出的,不要在循环中使用它。
此堆栈溢出答案是唯一一个捕获空格和短划线字符的答案:
1 2 3 4
| # For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found |
一个是:
1
| [ $(expr $mystring :".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no' |
- expr是瑞士军刀机构之一,通常可以做任何你需要做的事情,一旦你知道如何做,但一旦实施,你就永远不会记得为什么或如何做它正在做的事情,所以你永远不会再碰它,并希望它永远不会停止做它正在做的事情。
- @迈克尔,这个答案不对?我不明白。。。
- @我从来没有投反对票,我只是假设为什么投反对票。谨慎的评论我确实使用expr,在极少数情况下,当可移植性阻止使用bash(例如,跨旧版本的不一致行为)、tr(各地不一致)或sed(有时速度太慢)时。但从个人经验来看,每当重新阅读这些expr主义时,我必须回到手册页。所以,我只想评论一下,expr的每一个用法都会被评论…
- 曾经有一段时间,你所拥有的一切都是原来的伯恩贝壳。它缺少一些通常需要的特性,因此实现了诸如expr和test这样的工具来执行这些特性。在当今这个时代,通常有更好的工具,其中许多都内置于任何现代外壳中。我想江户十一〔七〕号仍然在那里,但似乎没有人失踪江户十一〔二〕号。
1
| [[ $string == *foo* ]] && echo"It's there" || echo"Couldn't find" |
- 我还要补充一点,末尾的echo"Couldn't find语句是返回这些匹配命令的0退出状态的一个好技巧。
- @nicodjimenez使用此解决方案不能再以退出状态为目标。退出状态被状态消息吞没…
- 这正是我的意思…如果没有|| echo"Couldn't find",那么如果没有匹配项,则返回错误退出状态;如果运行的是CI管道,则可能不希望返回错误退出状态,例如,希望所有命令都返回非错误退出状态。
grep -q可用于此目的。
使用awk的方法相同:
1 2 3
| string="unix-bash 2389"
character="@"
printf '%s'"$string" | awk -vc="$character" '{ if (gsub(c,"")) { print"Found" } else { print"Not Found" } }' |
输出:
Not Found
1 2 3
| string="unix-bash 2389"
character="-"
printf '%s'"$string" | awk -vc="$character" '{ if (gsub(c,"")) { print"Found" } else { print"Not Found" } }' |
输出:
Found
原始来源:http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
- echo是不可移植的,您应该改为使用printf '%s'"$string"。我正在编辑答案,因为用户似乎不再存在。
我喜欢SeD。
1 2 3
| substr="foo"
nonsub="$(echo"$string" | sed"s/$substr//")"
hassub=0 ; ["$string" !="$nonsub" ] && hassub=1 |
编辑,逻辑:
使用sed从字符串中移除子字符串的实例
如果新字符串与旧字符串不同,则存在子字符串
- 请增加一些解释。传授底层逻辑比仅仅给出代码更重要,因为它有助于操作人员和其他读者自己解决这个和类似的问题。
我的.bash_简介以及我如何使用grep如果路径中包含我的2个bin dirs,请不要附加它们
1 2 3 4 5 6 7 8 9 10 11
| # .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 |
- 这是一个答案吗?
- 投票赞成。当grep更强大的时候,为什么还要学习bash是如何做到的呢?还可以通过与模式列表进行匹配来进一步扩展它:grep -q -E 'pattern1|...|patternN'。
我发现经常需要这个功能,所以我在我的.bashrc中使用了一个自制的shell函数,它允许我尽可能频繁地重复使用它,并有一个易于记忆的名称:
1 2 3 4 5 6 7 8 9
| function stringinstring()
{
case"$2" in
*"$1"*)
return 0
;;
esac
return 1
} |
为了测试$string1是否包含在$string2中(比如123abc abc),我只需要运行stringinstring"$string1""$string2"并检查返回值,例如
1
| stringinstring"$str1""$str2" && echo YES || echo NO |
- ["$str"==$substr]]&;&;echo是echo否
- 我敢肯定,只有非常老的炮弹才需要x黑客。
此处回答问题的扩展:https://stackoverflow.com/a/8811800/712666
此解决方案使用特殊字符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| # contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
string="$1"
substring="$2"
if echo"$string" | $(type -p ggrep grep | head -1) -F --"$substring">/dev/null; then
return 0 # $substring is in $string
else
return 1 # $substring is not in $string
fi
}
contains"abcd""e" || echo"abcd does not contain e"
contains"abcd""ab" && echo"abcd contains ab"
contains"abcd""bc" && echo"abcd contains bc"
contains"abcd""cd" && echo"abcd contains cd"
contains"abcd""abcd" && echo"abcd contains abcd"
contains"""" && echo"empty string contains empty string"
contains"a""" && echo"a contains empty string"
contains"""a" || echo"empty string does not contain a"
contains"abcd efgh""cd ef" && echo"abcd efgh contains cd ef"
contains"abcd efgh""" && echo"abcd efgh contains a space"
contains"abcd [efg] hij""[efg]" && echo"abcd [efg] hij contains [efg]"
contains"abcd [efg] hij""[effg]" || echo"abcd [efg] hij does not contain [effg]"
contains"abcd *efg* hij""*efg*" && echo"abcd *efg* hij contains *efg*"
contains"abcd *efg* hij""d *efg* h" && echo"abcd *efg* hij contains d *efg* h"
contains"abcd *efg* hij""*effg*" || echo"abcd *efg* hij does not contain *effg*" |
尝试oo bash它是一个用于bash 4的oo样式字符串库。它支持德国Umlauts。它是用bash写的。Many functions are available: -base64Decode, -base64Encode, -capitalize, -center, -charAt, -concat, -contains, -count, -endsWith, -equals, -equalsIgnoreCase, -reverse, -hashCode, -indexOf, -isAlnum, -isAlpha, -isAscii, -isDigit, -isEmpty, -isHexDigit,edoccx1〔39〕,-isSpace,-isPrintable,-isUpperCase,-isVisible,-lastIndexOf,-length,-matches,-replaceAll,-replaceFirst,-startsWith,-substring,-swapCase,EDOCX11〔52〕,edcx1〔53〕,-toString,-toString,-lastIndexOf,-length,-matches,-replaceAll,-replaceFirst,-replaceFirst,-replaceFirst,-startsWith-toUpperCase、-trim、-zfill。
查看包含示例:
1 2 3 4 5
| [Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false |
oobash在sourceforge.net上提供。
完全匹配的单词:
1 2 3 4 5 6 7
| string='My long string'
exactSearch='long'
if grep -E -q"\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
then
echo"It's there"
fi |
我使用这个函数(不包括一个依赖项,但很明显)。它通过了下面所示的测试。如果函数返回的值大于0,则会找到字符串。您可以很容易地返回1或0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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
} |