How to compare strings in Bash
如何将变量与字符串进行比较(如果匹配,则执行某些操作)?
- 因此mywiki.wooledge.org湖:bashfaq / 031号
在if语句中使用变量
1 2 3
| if ["$x" ="valid" ]; then
echo"x has the value 'valid'"
fi |
如果你想在它们不匹配的时候做点什么,用!=替换=。您可以在各自的文档中了解更多关于字符串操作和算术操作的信息。
我们为什么要在
$x周围使用报价?
您需要在$x周围加引号,因为如果它是空的,那么您的bash脚本会遇到如下语法错误:
==运算符的非标准使用
注意,bash允许==用于与[相等,但这不是标准。
使用第一种情况,其中$x周围的引号是可选的:
1
| if [["$x" =="valid" ]]; then |
或者使用第二种情况:
1
| if ["$x" ="valid" ]; then |
- 这与意外的操作员错误中给出的公认答案有什么关系?我在使用["$1" =="on" ]时也犯了同样的错误。将此更改为["$1"="on"]解决了问题。
- 难道不是代码中的EDOCX1[1]吗?
- 空间是需要的。
- @Johnfeminella在写bash脚本时,应该只有一个=,而不是两个。
- @用户13107:不准确。对于字符串比较,==与=相同。(另外,您总是希望使用==进行数值比较。)
- @使用==的johnfeminella给出了Unexpected Operator Error用于piotr提到的字符串。
- @用户13107那么你可能使用的是sh,而不是bash。这是关于bash的问题。
- 如果我用if [ $x =="valid" ]; then或if [""$x"" =="valid" ]; then而不是if ["$x" =="valid" ]; then有什么区别?
- @如果$x包含空格,则第一个helinwang失败。第二个没有任何意义(空字符串,后面是无引号的变量,后面是空字符串)。
- 如果字符串包含冒号(例如:"test:test2"),如何比较该字符串?我甚至无法比较相同的字符串-例如:-如果["test:test2"="test:test2"];那么…
- @亲爱的,你可能想确认一下你没有打字错误。那应该行得通。例如,["foo:bar" =="foo:bar" ] && echo"equal"打印了我所期望的。
- @它说:->[:test:test2.t:unexpected operator我的脚本是这样的:if ["test:test2.t" =="test:test2.t" ]; then echo"Quoka App found on your device."。
- @Johnfeminella:当我使用变量并将其与字符串进行比较时,也会发生同样的事情。
- @我用Ubuntu14.04LTS来比较if [ 'testt' = 'testt' ]; then,它是有效的,但我认为它是用于数字比较。它仍然不能用于变量和字符串比较。
- 你确定你在使用bash吗?请仔细核对。同样,请在命令行尝试["foo:bar" =="foo:bar" ] && echo"equal",而不是在脚本中进行验证。如果你有一个特定的问题,你应该问一个新的stackoverflow问题,这样人们可以帮助你。
- @约翰菲梅内拉是的,我正在使用!/我甚至尝试在终端中输入bash,然后运行脚本,但仍然没有成功。我将在研发之后开始新问题。
- 可能值得注意的是,您不能使用[ $x -eq"valid" ]。-eq是整数而不是字符串的比较运算符。
- 注意:请务必使用空格:这不起作用:if ["$x"=="valid" ]!
- 没有if then的语法和它的语法相同吗?
- 是的,同意@craq的评论,错误integer expression expected引导我来到这里——我错误地使用-eq运算符进行字符串比较;现在我使用=。
- @亚历克斯,在哪种情况下(如果有的话),我需要使用模式["x$yes" =="xyes"],即用x前缀变量和字符串文字?那是旧时代的遗物还是在某些情况下真的需要它?
- @lanoxx stackoverflow.com/a/3093491/887836实际上,如果$yes扩展为nothing,那么脚本将因无效语法而终止。
- @alex,"x$yes"习语只需在使用现代测试标记posix标准过时的使用模式时消除歧义(具体来说,使用-a、-o、(和)生成结合多个测试的单个test表达式)。在遵循1991年后炮弹的良好实践时,这是没有价值的。
- @Alex,当$yes扩展到Nothing时避免无效语法的正确方法是将其引用为"$yes"。您不需要使用x前缀,并且该前缀不会修复引用代码可以解决的未引用代码中的其他错误。
或者,如果不需要其他条款:
1
| ["$x" =="valid" ] && echo"x has the value 'valid'" |
- 如果您确实需要一个else子句,并且想要创建一个疯狂的一行程序:["$X"=="valid"]&;&;echo"valid"echo"invalid"
- @马特怀特:这通常是个坏主意,因为echo可能会失败。
- 即使是那些可能出现的,美和优雅的方式,从马尔科和马特怀特
- @没问题,用["$X" =="valid" ] || ( echo invalid && false ) && echo"valid" 。
- 小心这个短版本。当没有其他值时,返回值将是1,在带有-e标志的bash中,它将导致脚本停止,并且CI也不接受返回值1。
- @12431234123412341234123 { echo invalid && false; }比( echo invalid && false )更有效,因为它避免了为不必要的子层付费。
- 在posix sh中,==代替=是未定义的。[SC2039 ]
要比较字符串和通配符,请使用
1 2 3 4 5
| if [["$stringA" == *$stringB* ]]; then
# Do something here
else
# Do Something here
fi |
- 通配符只能在右侧使用非常重要!还要注意通配符周围缺少的"。(btw:+1表示通配符!)
- 扩展$stringB必须被引用(顺便说一下,左侧不需要被引用):if [[ $stringA = *"$stringB"* ]]; then。
- 我正在尝试对文件路径中的文件名使用相同的通配符逻辑。但它对我不起作用。尝试了这里提供的所有不同的通配符字符串。但它总是适用于其他情况。在我的例子中,stringa是一个文件路径/tmp/file,stringb是"file"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| a="abc"
b="def"
# Equality Comparison
if ["$a" =="$b" ]; then
echo"Strings match"
else
echo"Strings don't match"
fi
# Lexicographic (greater than, less than) comparison.
if ["$a" \<"$b" ]; then
echo"$a is lexicographically smaller then $b"
elif ["$a" \>"$b" ]; then
echo"$b is lexicographically smaller than $a"
else
echo"Strings are equal"
fi |
笔记:
if和[和]之间的空间很重要。
>和<是重定向运算符,因此分别用\>和\<对字符串进行转义。
- 感谢您按字母顺序比较字符串
- 我的问题是,$a实际上有""包围它作为字符串文字值的一部分,因此我必须使用escape字符对$b比较这些值。我在运行bash -x ./script.sh之后就发现了这一点,-x标志允许您查看每个执行的值并帮助进行调试。
- 请注意,字母顺序比较不是POSIX标准化的,因此它不能保证在非GNU平台/非bash shell上工作。只有pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html的操作才能保证可移植。
我必须在一点上不同意其中一条评论:
1
| ["$x" =="valid" ] && echo"valid" || echo"invalid" |
不,那不是一条疯狂的单行线
只是它看起来像一个,嗯,不起眼的…
在某种程度上,它使用共同的模式作为一种语言;
在你学会了语言之后。
事实上,读起来很好
它是一个简单的逻辑表达式,有一个特殊的部分:逻辑运算符的延迟计算。
1
| ["$x" =="valid" ] && echo"valid" || echo"invalid" |
每一部分都是一个逻辑表达式;第一部分可能是对的,也可能是错的,另外两部分总是对的。
1 2 3 4 5 6 7
| (
["$x" =="valid" ]
&&
echo"valid"
)
||
echo"invalid" |
现在,当它被评估时,第一个被检查。如果为假,则大于逻辑的第二个操作数,且后面的&&不相关。第一个不是真的,所以它不能是第一个,第二个也是真的。现在,在这种情况下,逻辑的第一个方面或||错误,但如果另一个方面(第三部分)是正确的,则可能是正确的。
因此,第三部分将被评估——主要是作为副作用编写消息。(其结果为:0为真,我们在这里不使用)
其他的情况是相似的,但更简单——我保证!容易阅读!(我没有,但我认为作为一名留着灰胡子的Unix老兵,这对我有很大帮助。)
- ... && ... || ...通常不受欢迎(抱歉,灰胡子的Unix老兵,你一直都是错的),因为它在语义上并不等同于if ... then ... else ...。别担心,这是一个常见的陷阱。
- @Gniourf-Gniourf-Op没有错——他们也不像你所说的那样无知。... && ... || ...是一个完全有效的模式,也是一个常见的bash习惯用法。使用它确实规定了事先的知识(如果观众中有初学者,这可能是很好的记住),但OP有头发证明他们知道如何避免打开井盖。
- @ebpa如果后面的语句返回值false,执行会继续到后面的语句吗?如果是这样的话,那就错了,也许这就是Gniourf的建议
- @tsg它是一个有效的模式,因为echo"valid"被视为不变量;它总是返回0("成功")。您可以在那个位置替换命令,但是如果您不确定它总是返回0,那么您可能会在路上遇到麻烦(因此模式需要事先了解)。我并不认为这是一个理想的模式;只是它是合法的,并且可以适当地使用(例如,使用echo语句)。如果您的路径是fubar或系统中缺少/bin/echo,那么fwiw echo"valid"在技术上可能会失败并返回非零,但之后您会遇到更大的问题。
- 我认为Echo只是一个例子。后面的语句可能仍然返回非零值
- @gniurf_gniurf+1用于发布bash陷阱的链接!非常有用!
您还可以使用用例/ESAC
1 2 3
| case"$string" in
"$pattern" ) echo"found";;
esac |
下面的脚本逐行从名为"testonhis"的文件中读取,然后将每一行与一个简单字符串、一个带有特殊字符的字符串和一个正则表达式进行比较。如果不匹配,则脚本将打印行"o/w not"。
bash中的空间非常重要。所以下面就行了
1
| ["$LINE" !="table_name" ] |
但以下不会:
1
| ["$LINE" !="table_name"] |
所以请按原样使用:
1 2 3 4 5 6
| cat testonthis | while read LINE
do
if ["$LINE" !="table_name" ] && ["$LINE" !="--------------------------------" ] && [["$LINE" =~ [^[:space:]] ]] && [["$LINE" != SQL* ]]; then
echo $LINE
fi
done |
- 使用此方法浏览文件。也就是说,除去uuoc和其他东西。
如果输入只有几个有效的条目,我可能会使用regexp匹配。例如,只有"开始"和"停止"才是有效的操作。
1 2 3
| if [["${ACTION,,}" =~ ^(start|stop)$ ]]; then
echo"valid action"
fi |
请注意,我使用双逗号将变量$ACTION小写。还要注意,这在太老的bash版本上不起作用。
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,完全匹配:
享受。
我这样做是为了与bash、dash(sh)兼容:
1 2 3 4 5 6 7 8 9 10
| testOutput="my test"
pattern="my"
case $testOutput in (*"$pattern"*)
echo"if there is a match"
exit 1
;;
(*)
! echo there is no coincidence!
;;esac |