使用sh shell比较字符串

265

我正在使用SH shell,尝试将一个字符串与一个变量的值进行比较,但if条件始终为真。为什么会这样?

以下是一些代码:

Sourcesystem="ABC"

if [ "$Sourcesystem" -eq 'XYZ' ]; then 
    echo "Sourcesystem Matched" 
else
    echo "Sourcesystem is NOT Matched $Sourcesystem"  
fi;

echo Sourcesystem Value is  $Sourcesystem ;

即使这样也不起作用:

Sourcesystem="ABC"

if [ 'XYZ' -eq "$Sourcesystem" ]; then 
    echo "Sourcesystem Matched" 
else
    echo "Sourcesystem is NOT Matched $Sourcesystem"  
fi;

echo Sourcesystem Value is  $Sourcesystem ;

其次,我们能否将其与空值或空字符串匹配?


在Bourne shell中,您不需要额外的';'。当我在Bourne shell中测试运行脚本时,if条件为false。它将首先给出警告:[: ABC:期望整数表达式。输出是:“Sourcesystem is NOT Matched ABC”。正如其他人所评论的那样,-eq用于整数比较。在Bourne shell(#!/bin/sh)中使用单个等号进行字符串比较。您的shell应该在第一时间纠正您。 - Kemin Zhou
8
投票重新开放。引用的重复内容是针对 Bash Shell 而不是无力的 Sh Shell,后者有时是一个 Posix Shell 或 Dash。 - jww
1
同意并投票赞成。shbash的关系就像CC++一样。尽管第一个编写的代码在第二个中有效,但第二个的答案不能保证在第一个中正常工作。 - btilly
7个回答

373

你应该使用=运算符进行字符串比较:

Sourcesystem="ABC"

if [ "$Sourcesystem" = "XYZ" ]; then 
    echo "Sourcesystem Matched" 
else
    echo "Sourcesystem is NOT Matched $Sourcesystem"  
fi;

man test 告诉我们可以使用 -z 来匹配空字符串。


4
无需引用“ABC”或“XYZ”。 - ceving
51
如果您的变量可能包含空格,则需要使用引号。 - William Everett
1
调整了示例以使该部分更清晰 @WilliamEverett。 - Per Lundberg
1
如果两个字符串包含多行,其中第一行相等但后续行不同,则此方法在sh和bash(macOS 11.2)中无法正常工作-然后我始终会得到一个=测试的true。然而,在macOS的新zsh中,我甚至可以省略引号,如[ $a = $b ],并获得多行字符串的正确结果。 - Thomas Tempelmann
1
@Thomas - OP 的问题特别涉及到 sh 而不是 bash 或 zsh。 OP 的示例也永远不会是多行字符串。多行字符串应该采用不同的方法,而不是依赖于 zsh 的特性,除非您在专门的 zsh 环境中工作。定位 sh 通常意味着您需要高度的可移植性,因为并非所有环境都可以使用 bash 和/或 zsh。我在 macOS 上,并且可以定位 zsh,但是当我的脚本移动到我无法控制的 Linux 系统上时,它们将因为 zsh 不存在而无法运行。 - Stephen P

98

-eq 用于比较整数。请使用 = 替代。


14
请注意不要使用双等号 "=="。 - Rodrigo Caballero

54

使用等于号 '=' 代替 'eq' 来比较整数,例如:

示例:

if [ 'AAA' = 'ABC' ];
then 
    echo "the same" 
else 
    echo "not the same"
fi

祝你好运


4
注意:如果你在比较变量,确保使用"$VAR"而不仅是 $VAR - Sridhar Sarnobat
请注意,如果您要将变量与字符串进行比较 [ $(VAR) = "ABC" ] - Jesse H.

33

我曾经遇到过同样的问题,做这个

if [ 'xyz' = 'abc' ]; then
  echo "match"
fi

注意空格。在这种情况下,在=符号之后和之前使用空格非常重要。

查看“其他比较运算符”。


4
在Dockerfile中:/bin/sh: 1: [: =: 意外的操作符 - holms
你链接了bash的文档,但OP问的是/bin/sh。 - Dan Tenenbaum

12

-eq 是用于比较整数的shell比较运算符。如果要比较字符串,您需要使用=


3

我测试过4个shell,ABC -eq XYZzshkshtest内置中被评估为真。该表达式在/usr/bin/test以及dashbash的内置中评估为假。在kshzsh中,字符串被转换为数字值,并且因为它们都是0,所以相等。在我看来,kshzsh的内置行为是不正确的,但是test规范对此存在歧义。


1
感谢测试。这就是Bourne shell流行的原因。 - Kemin Zhou
使用 [ 或内置的 test 后,zsh 明显输出 _: integer expression expected_。也许您正在强制执行 *[[*,将字符串作为 显著整数进行评估,因此两者都被评估为 0。 - Mario G
@code933k 哪个版本?如果行为已经改变,我也不会感到惊讶。 - William Pursell
@WilliamPursell zsh 5.7.1 - Mario G

3

-eq 是一个数学比较运算符。我从未将其用于字符串比较,而是使用 ==!= 进行比较。

if [ 'XYZ' == 'ABC' ]; then   # Double equal to will work in Linux but not on HPUX boxes it should be if [ 'XYZ' = 'ABC' ] which will work on both
  echo "Match"
else
  echo "No Match"
fi

26
请注意,运算符 == 并非适用于所有的 shell。在比较字符串时,应该使用 = 运算符,而 == 有时是它的同义词。 - Omer Dagan
这个答案对于/bin/sh脚本是错误的,会失败。在macOS上,“test”命令(也可用作“[”)将“=”视为“==”。但在Linux上不是这样。 - neuhaus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接