Bash、Dash和字符串比较

50

我正在尝试在一个简单的shell脚本中比较两个字符串。 我一直使用的是/bin/sh而不是/bin/bash,在经过无数个小时的调试之后,发现sh(实际上是dash)无法处理这段代码块:

if [ "$var" == "string" ]
then
    do something
fi

如何使用 /bin/sh 以可移植的方式比较字符串?我知道可以通过使用 != 来执行相反的操作,但我想知道是否有更清晰、可移植的方法。

什么是使用 /bin/sh 可移植比较字符串的方法?我知道可以使用 != 进行相反操作,但我想了解更简洁、可移植的方法。


2
你可以使用[[ $var == "string" ]],这是POSIX标准,但可选的(据我所知)。或者你可以使用[ "$var" = "string" ]。请注意,在单括号版本中,变量周围的 "" 是必需的:如果 $var 为空,则需要它。 - Johannes Schaub - litb
2
重要的部分是$var周围的引号,就像litb所提到的那样。如果没有引号,则[ $var = "value" ]将变成[ = "value" ],这会使shell相当地混乱。否则,当您遇到一个空变量时,您可能会看到类似于_"[: =: unary operator expected"_的错误。 - D.Shawley
我理解 "$var" vs. $var 的区别,我的问题在于 == 和 = 的区别。 - LiraNuna
1
[[]]是由POSIX保留的,但并没有明确定义。我认为它只是保留了Korn特性。 - TheBonsai
5个回答

73

dash是一个非常严格的POSIX shell,如果在dash上能够工作,那么它几乎肯定也可以在其他POSIX shell上工作。

尝试一下:

if [ "$var" = "string" ]
then
    some_command
fi

8
如果您在想“这里与问题中的语法有什么不同”,那么它使用的是=而不是== - davnicwil
你可以如何在这个例子中使用通配符? 我尝试了 if [ "$OSTYPE" = "linux"* ]; then 但它无法匹配例如 linux-arm... - Pitto

9
为什么会有可能你的脚本被“错误”的 shell 运行?我认为你可以通过在脚本顶部使用标准的 sh-bang 行来将其作为产品前提条件。
#!/bin/bash

即使用户使用不同的shell,其他shell通常仍然存在,如果不存在,则会简单地抱怨并声明它们是先决条件。完全相同的方式,特定的内核级别或awk的存在可以成为先决条件。对于您的特定问题,我相信sh和bash都允许单个'='用于字符串比较-这是POSIX行为。
if [ "a" = "a" ]; then
    echo yes
fi

yes

3
“为什么你的脚本会被“错误”的shell运行的可能性甚至存在?” - 是否有可能控制Autoconf使用哪个shell?(这就是我正在寻找答案的原因) - jww

6
请使用=代替==。比较由test(1)处理。/usr/bin/[通常是指向/usr/bin/test的链接。唯一的区别是如果在shell脚本中使用[,则还需要]
请注意,bash具有内置的test/[,因此实际上不使用/usr/bin/test

1
是否有关于内置的test和单个或双重等号的官方规范? - Massimo

1
已经发布的答案无疑是正确的,但值得注意的是,有时参数扩展也可以发挥同样的作用,可能还具有更多的灵活性。
% p() { printf 'notvar = %b\n' "${notvar##"${string1}"}${string2}" ; }
% string1='some stuff about things\c'
% string2='some different stuff maybe'
% notvar="$string1" p
> 'some different stuff maybe'
% notvar="$string2" p
> 'some stuff about things'

好的,所以上面的内容本身并不是非常有用,但也要考虑到您可以使用类似的方法来测试这里文档中的变量,必要时进行内联变量赋值(在一定程度上...),甚至只是作为编写第一个语句更短(和更快!)的手段。

[ ! "${var##"string"}" ] && _MATCH || _NOMATCH

甚至连……
[ ${#var#*"${s=string}"} -lt ${#var} ] && _SUB_STRING_TEST=TRUE

可能甚至...
% p() { printf '%s is %s of %s' "$2" "${var_chk-not}" "$1"
> }<<HEREDOC
> ${in="${1##*"${2}"*}"}
> ${in:-
>     ${in="${1##"${2}"}"}
>     ${in:-${var_chk=all}
>     ${var_chk=some}
> }
> HEREDOC
%

3
除了试图赢得一个混淆竞赛,我不确定我看到这些技术的重大好处。 - swdev
哇...我需要有人用通俗易懂的语言解释一下 :) - Tomofumi

-3

你可以使用 awk

awk 'BEGIN{
 string1="test"
 string2="tes1t"
 if(s1==s2){
    print "same string"
 }else{
    print "not same"
 }
}'

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