【问题标题】:How do I compare two string variables in an 'if' statement in Bash? [duplicate]如何在 Bash 的“if”语句中比较两个字符串变量? [复制]
【发布时间】:2010-11-25 13:39:33
【问题描述】:

我正在尝试让if 语句在Bash 中工作(使用Ubuntu):

#!/bin/bash

s1="hi"
s2="hi"

if ["$s1" == "$s2"]
then
  echo match
fi

我尝试了各种形式的if 语句,使用[["$s1" == "$s2"]],带和不带引号,使用===-eq,但我仍然收到以下错误:

[嗨:找不到命令

我查看了各种网站和教程并复制了它们,但它不起作用 - 我做错了什么?

最后,我想说如果$s1 包含$s2,那我该怎么做呢?

我只是计算了一下空格...:/我怎么说包含

我试过了

if [[ "$s1" == "*$s2*" ]]

但是没有用。

【问题讨论】:

标签: bash if-statement scripting


【解决方案1】:

对于字符串相等比较,使用:

if [[ "$s1" == "$s2" ]]

对于字符串不等于比较,使用:

if [[ "$s1" != "$s2" ]]

对于包含ba,使用:

if [[ $s1 == *"$s2"* ]]

(并确保在符号之间添加空格):

不好:

if [["$s1" == "$s2"]]

好:

if [[ "$s1" == "$s2" ]]

【讨论】:

  • stackoverflow.com/a/229606/376454 我不得不使用这个答案将变量与固定字符串进行比较。
  • IRC 上挑剔的家伙告诉我你应该使用 if [[ "$s1" == "$s2" ]] 或 case。
  • 双等号在第一种情况下是错误的。 Bash 可以容忍它,但可移植的变体是if [ "$s1" = "$s2" ]。另请参阅Rahul's answer
  • 嗨,我想知道为什么这样不好 -> if ["$s1" == "$s2"] 空格有什么意义?
  • @Sangimed, [ 是一个命令(实际上是命令的另一个名称test);如果你运行which [,你会看到磁盘上实际上有一个可执行文件(尽管shell 可能提供一个内置的实现作为性能优化)。就像您必须在要打印的文件名称之前在命令名称 ls 之间放置一个空格一样,您需要在命令名称 [ 及其第一个参数之后放置一个空格,并且在它传递的每个参数之间(如果调用为[ 而不是test,它期望它的最后一个参数是])。
【解决方案2】:

你需要空格:

if [ "$s1" == "$s2" ]

【讨论】:

  • 只是想说确保在开始和结束的方括号和"$s1" == "$s2" 语句之间留一个空格,否则它将不起作用。此外,这也有效:if test "$s1" = "$s2"
  • 一切都与空间有关 :))
  • @racl101 的第一条评论为我解决了这个问题。谢谢!!
  • == 不适用于 test 的 ash、dash 或其他地方的基线 POSIX 实现。请改用=
【解决方案3】:

您应该小心在 '[' 符号和双引号之间留一个空格,其中变量包含以下内容:

if [ "$s1" == "$s2" ]; then
#   ^     ^  ^     ^
   echo match
fi

^s 显示您需要留下的空格。

【讨论】:

  • 非常感谢您指出必要的空间。解决了我的问题。今天刚开始bash,好像很多时候空格会导致错误,即声明变量等。
  • 包含; thenfi 部分的奖励积分。
  • == 不适用于 test 的 ash、dash 或其他地方的基线 POSIX 实现。请改用=
【解决方案4】:

我推荐这个:

if [ "$a" = "$b" ]

注意左/右括号和变量之间的空格,以及包裹“=”符号的空格。

另外,请注意您的脚本标题。用不着就不一样了

#!/bin/bash

#!/bin/sh

Here's the source.

【讨论】:

  • 赞成,但在阅读 ABS 时请务必小心。链接到更权威的来源可能是首选。
  • 感谢您的建议,确保更权威的来源更准确。
  • /bin/sh: 1: [: 缺失]
  • @holms,当按照此处给出的精确使用时,OP 的代码不会发生这种情况。您需要显示您的确切使用情况。
【解决方案5】:

Bash 4+ 示例。注意:当单词包含空格等时,不使用引号会导致问题。始终在 Bash IMO 中引用。

以下是一些 Bash 4+ 的示例:

示例 1,检查字符串中的“是”(不区分大小写):

if [[ "${str,,}" == *"yes"* ]] ;then

示例 2,检查字符串中的“是”(不区分大小写):

if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

示例 3,检查字符串中的“是”(区分大小写):

 if [[ "${str}" == *"yes"* ]] ;then

示例 4,检查字符串中的“是”(区分大小写):

 if [[ "${str}" =~ "yes" ]] ;then

示例 5,完全匹配(区分大小写):

 if [[ "${str}" == "yes" ]] ;then

示例 6,完全匹配(不区分大小写):

 if [[ "${str,,}" == "yes" ]] ;then

示例 7,完全匹配:

 if [ "$a" = "$b" ] ;then

【讨论】:

  • 很好的答案。打赌,如果它离顶部不远,它会得到更多的支持。
【解决方案6】:

我建议:

#!/bin/bash

s1="hi"
s2="hi"

if [ $s1 = $s2 ]
then
  echo match
fi

没有双引号,只有一个等于

【讨论】:

  • 是的,没错,我错过了空格。使用 "[ $s1 = $s2 ]" 它可以工作。
  • 为什么要省略双引号?在这种有限的特定情况下,它们是可选的,但无害,但在许多实际情况下,删除它们将是一个严重的错误。另见stackoverflow.com/questions/10067266/…
  • 试试s1='*'s2='*',你会发现省略双引号是一个严重的错误。
【解决方案7】:

这个问题已经有了很好的答案,但这里似乎在使用单等号 (=) 和双等号 (==) 之间存在轻微的混淆

if [ "$s1" == "$s2" ]

主要区别在于您使用的脚本语言。如果您使用的是 Bash,则在脚本的开头包含 #!/bin/bash 并将您的脚本保存为 filename.bash。要执行,请使用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 文件名”执行它,无论您使用单等号还是双等号,它都可以正常工作。另一件事是,如果您使相同的文件(没有 shebang 和任何扩展名)可执行,那么您可以像 ./filename 一样执行它(无论是单等还是双等)。(在 Arch linux 上用 bash 4.3.46 尝试过)。
  • 如果你通过运行 say "bash filename" 来执行文件 - 那么你只是将 'filename' 作为参数传递给程序 'bash' - 这当然会导致 bash 运行它。但是,如果您设置“文件名”执行权限,并尝试通过例如“./文件名”运行它 - 那么您依赖于当前命令外壳的默认“执行”行为 - 这可能需要“#!(外壳) " 脚本开头的行,以便工作。
【解决方案8】:
$ if [ "$s1" == "$s2" ]; then echo match; fi
match
$ test "s1" = "s2" ;echo match
match
$

【讨论】:

  • 在 Bash 中允许使用双等号,但在某些其他方言中则不允许。为了可移植性,应该首选单个等号,如果您只针对 Bash,则双括号 [[ 扩展在多功能性、健壮性和便利性方面会更胜一筹。
【解决方案9】:

我现在无法访问 Linux 机器,但 [ 实际上是一个程序(和内置 Bash),所以我认为你必须在 [ 和第一个参数之间放置一个空格。

另请注意,字符串相等运算符似乎是单个 =

【讨论】:

  • 符号 [ 曾经是指向 /bin/test 的链接(反之亦然)。在 ubuntu 16.04 上显然不再是这种情况了;不知道变化发生在何时何地。
【解决方案10】:

这更像是一个澄清而不是一个答案!是的,线索在错误信息中:

[嗨:找不到命令

这表明您的“hi”已连接到“[”。

与更传统的编程语言不同,在 Bash 中,“[”是一个命令,就像更明显的“ls”等一样 - 它不是因为它是一个符号而被特殊对待,因此“[”和(替换为) "$s1" 在你的问题中紧挨着,被连接起来(对于 Bash 来说是正确的),然后它会尝试在该位置找到一个命令:[hi - 这是 Bash 未知的。

在 C 和其他一些语言中,“[”将被视为不同的“字符类”,并且与后面的“hi”不相交。

因此您需要在开头的“[”之后留一个空格。

【讨论】:

    【解决方案11】:

    用途:

    #!/bin/bash
    
    s1="hi"
    s2="hi"
    
    if [ "x$s1" == "x$s2" ]
    then
      echo match
    fi
    

    在里面添加一个额外的字符串会更安全。

    您也可以对单行命令使用另一种表示法:

    [ "x$s1" == "x$s2" ] && echo match
    

    【讨论】:

    • “更安全”是什么意思?为了完整和清晰起见,解释任何此类限定非常重要。
    • 事实上它并不安全,现在我知道如果你不引用它会更安全,如果其中一个是空的,这样可以防止语法错误
    【解决方案12】:

    对于带有纯 Bash 且没有 test,但非常丑陋的版本,请尝试:

    if ( exit "${s1/*$s2*/0}" )2>/dev/null
    then
       echo match
    fi
    

    解释:在( )中打开了一个额外的子shell。如果有匹配,它会以 0 退出,如果没有匹配会引发错误(丑陋),它会尝试以 $s1 退出。此错误指向/dev/null

    【讨论】:

    • 一点也不差。就像解释和 sed 正则表达式一样。我从来不需要那样使用 subshel​​l。据我所知,您可以使用 command 或 $(command) 获得输出。我相信你可以测试它然后让它变得更好。
    • 这在s2 包含globs 的情况下被轻易破坏:要解决此问题,您需要引用扩展$s2: "${s1/*"$s2"*/0}"。但是还有其他一些无法修复的细微错误:例如,如果 s10 的列表:s1=000000; s2=some_other_stuff 将要求匹配。所以我强烈建议不要使用这种方法!另一个错误:s1=--; s2=stuff。从 bash 4.4 开始,s1=--help; s2=stuff 也会向标准输出发送垃圾邮件。
    猜你喜欢
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    相关资源
    最近更新 更多