How do I compare two string variables in an 'if' statement in Bash?
我正在尝试在bash中使用if语句(使用ubuntu):
1 2 3 4 5 6 7 8 9
| #!/bin/bash
s1="hi"
s2="hi"
if ["$s1" =="$s2"]
then
echo match
fi |
我试过各种形式的if声明,使用[["$s1" =="$s2"]],加引号和不加引号,使用=、==和-eq,但我仍然得到以下错误:
[hi: command not found
我浏览过各种网站和教程,并复制了它们,但它不起作用——我做错了什么?
最后,我想说如果$s1包含$s2,我该怎么做?
我只是计算了一下空间。:/我怎么说包含?
我试过
但它不起作用。
- 另请参见stackoverflow.com/questions/9581064/…
对于字符串比较,请使用:
对于含有b的a而言,使用:
(并确保在符号之间添加空格):
坏的:
好:
- stackoverflow.com/a/229606/376454我不得不用这个答案将变量与固定字符串进行比较。
- IRC上挑剔的家伙告诉我,如果是[["$s1"=="$s2"]]或case,你应该使用。
- 在第一种情况下,双等号是一个错误。bash可以接受,但是便携式的变体是if ["$s1" ="$s2" ]。另见Rahul的答案
- [不幸的是,并非所有炮弹都能使用。在travis ci上,它给出:[[: not found。
- 嗨,我想知道为什么这是坏的->如果["$s1"="$s2"]空格有什么意义?
- posix test只将=指定为字符串比较运算符。==是不可移植的扩展。因此,使用["$str1" ="$str2" ]而不是["$str1" =="$str2" ]是一个更好的习惯(它不适用于基线posix shell,如dash)。
- @sangimed,[是一个命令(实际上是名为test的命令的另一个名称);如果运行which [,您将看到磁盘上实际上有一个可执行文件(即使shell可以提供内置实现作为性能优化)。就像在要打印的文件名之前必须在命令ls的名称之间加上一个空格一样,您需要在[命令名及其第一个参数之后加上一个空格,以及在它传递的每个参数之间加上一个空格(如果调用为[而不是test,它希望最后一个参数o是]。
您需要共享空间:
- 只是想说,要确保在方括号的开始和结束和"$s1" =="$s2"语句之间留一个空格,否则它将不起作用。同样,这也是可行的:if test"$s1" ="$s2" 。
- 一切都是为了空间:)
- @racl101的第一条评论为我解决了这个问题。谢谢!!
- ==不适用于ash、dash或其他地方,它是test的基线POSIX实现。用=代替。
在变量包含此内容的"["符号和双引号之间应注意留有空格:
1 2 3 4
| if ["$s1" =="$s2" ]; then
# ^ ^ ^ ^
echo match
fi |
EDCOX1×2表示需要离开的空白空间。
- 非常感谢您指出了必要的空间。解决了我的问题。今天刚开始的bash,似乎很多时候空间会导致错误,例如声明变量等。
- 包含; then和fi部分的奖励积分。
- ==不适用于ash、dash或其他地方,它是test的基线POSIX实现。用=代替。
我建议这个:
注意开/闭括号和变量之间的空白,以及环绕"="符号的空白。
另外,注意脚本头。不管你用什么都不一样
或
这是来源。
- 向上投票,但阅读腹肌时一定要小心。最好是链接到更权威的来源。
- 谢谢你的建议,当然一个更权威的来源更准确。
- /bin/sh:1:[:丢失]
- @福尔摩斯,如果按照这里给出的方式精确使用操作码,就不会发生这种情况。你需要展示你的确切用法。
我建议:
1 2 3 4 5 6 7 8 9
| #!/bin/bash
s1="hi"
s2="hi"
if [ $s1 = $s2 ]
then
echo match
fi |
没有双引号,只有一个等于。
- 是的,没错,我错过了空间。使用"[$s1=$s2]",它可以工作。
- 为什么省略双引号?在这种有限的特定情况下,它们是可选的,但无害的,但是在许多实际情况下,删除它们将是一个严重的错误。另请参见stackoverflow.com/questions/10067266/…
- 尝试使用s1='*'和s2='*',你会发现漏掉双引号是一个严重的错误。
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,那么在脚本的开头包含#!/bin/bash,并将脚本保存为filename.bash。要执行use bash filename.bash,则必须使用==。
如果使用sh,则使用#!/bin/sh,并将脚本保存为filename.sh。要执行使用sh filename.sh,则必须使用单个=。避免把它们混在一起。
- "你必须使用=="的说法是错误的。bash同时支持=和==。另外,如果在脚本开始时有#!/bin/bash,则可以使其成为可执行文件,并像./filename.bash那样运行(而不是文件扩展名很重要)。
- 太好了,我想我现在必须删除这个答案,但是如果你解释为什么不使文件可执行并且在文件名之前添加sh/bash来运行它,这将非常有帮助?
- 这对shebang和文件名的意义感到困惑。如果您正确地将#!/bin/sh或#!/bin/bash作为脚本的第一行,只需使用./filename运行它,实际文件名可以完全任意。
- 现在,这变得有趣了,即使您没有添加任何shebang和任何扩展名,并且使用"bash/sh filename"执行它,无论您使用的是单等号还是双等号,它都在工作。还有一件事,如果您使同一个文件(没有shebang和任何扩展名)可执行,那么您可以像/filename一样执行它(无论是单或双)。等于)。(在使用bash 4.3.46的Arch Linux上尝试过)。
- 如果您通过运行say"bash filename"来执行文件,那么您只是将"filename"作为参数传递给程序"bash",这当然会导致bash运行它。但是,如果您设置了"filename"执行权限,并尝试通过例如"./filename"来运行它,那么您将依赖于当前命令shell的默认"execute"行为,这可能需要""!(shell)"脚本开头的行,以便工作。
- falso说在bash中"必须使用"==,bash同时支持posix语法和扩展语法,所以=在这两个地方都可以工作,而==只在扩展shell中工作。
1 2 3 4 5
| $ if ["$s1" =="$s2" ]; then echo match; fi
match
$ test"s1" ="s2" ;echo match
match
$ |
- 在bash中允许使用双等号,但在其他一些方言中则不允许使用双等号。对于可移植性,应首选单等号,如果只针对bash,则双括号[[扩展将在多功能性、健壮性和方便性方面更优越。
我现在没有访问Linux设备的权限,但[实际上是一个程序(和bash内置),所以我认为您必须在[和第一个参数之间放置一个空格。
还要注意,字符串相等运算符似乎是一个=
- 符号[曾经是指向/bin/测试的链接(或者相反)。显然,Ubuntu16.04已经不再是这样了;不知道在哪里或什么时候发生了变化。
这比回答更清楚!是的,线索在错误消息中:
[hi: command not found
这表明您的"hi"已连接到"["。
与更传统的编程语言不同,在bash中,"["是一个命令,就像更明显的"ls"等一样。—它不被特别对待,仅仅是因为它是一个符号,因此"["和(替换的)"$s1"在您的问题中紧挨在一起,被连接(对于bash是正确的),然后它试图在tha中找到一个命令。T位置:【嗨—巴什不知道。
在C语言和其他一些语言中,"["将被视为一个不同的"字符类",并与下面的"hi"分离。
因此,在开口"["后需要一个空格。
对于纯bash和不带test但非常难看的版本,请尝试:
1 2 3 4
| if ( exit"${s1/*$s2*/0}" )2>/dev/null
then
echo match
fi |
说明:在( )中,一个额外的子壳被打开。如果匹配,则退出0;如果不匹配,则尝试退出$s1,这会导致错误(丑陋)。此错误指向/dev/null。
- 一点也不坏。就像解释和sed regexp一样。我从不需要用这种方式使用子外壳。如我所知,您可以使用command或$(command)获得输出。我相信你可以先测试一下然后再做得更好。
- 在s2包含globs的情况下,这一点被打破了:要解决这个问题,需要引用扩展$s2:"${s1/*"$s2"*/0}"。但还有其他一些不可能修复的细微缺陷:例如,如果s1是0的列表:s1=000000; s2=some_other_stuff将要求匹配。所以我强烈建议不要使用这种方法!另一个bug:s1=--; s2=stuff。从bash 4.4开始,s1=--help; s2=stuff还将垃圾邮件标准输出。
1 2 3 4 5 6 7 8 9
| #!/bin/bash
s1="hi"
s2="hi"
if ["x$s1" =="x$s2" ]
then
echo match
fi |
在内部添加额外的字符串使其更安全。
您还可以对单行命令使用其他符号:
1
| ["x$s1" =="x$s2" ] && echo match |
- "更安全"是什么意思?为了完整性和清晰性,解释任何此类资格都很重要。
- 事实上,它并不安全,现在我知道如果你不引用它会更安全,这样可以防止语法错误,如果其中一个是空的