【问题标题】:bash, dash and string comparisonbash、破折号和字符串比较
【发布时间】:2010-11-08 13:20:54
【问题描述】:

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

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

什么是使用/bin/sh 比较字符串的可移植方式?我知道我总是可以通过使用 != 来做相反的事情,但我想知道一种更清洁、更便携的方式。

【问题讨论】:

  • 您可以使用 [[ $var == "string" ]] ,这是 POSIX,但可选(afaik)。或者您使用 [ "$var" = "string" ] 。注意单括号版本中变量周围的"":如果$var为空,则需要它
  • 重要的部分是 litb 提到的 $var 周围的引号。如果没有引号,[ $var = "value" ] 将变为 [ = "value" ],这会使 shell 非常混乱。否则,当您遇到空变量时,您可能会看到类似 "[: =: unary operator expected" 的错误。
  • 我了解“$var” vs. $var,我的问题是 == vs. =
  • [[ ]] 被 POSIX 保留,但根本没有定义。它只是保留,因为我认为这是 Korn 的一项功能。

标签: bash dash-shell string-comparison


【解决方案1】:

dash 是一个非常严格的 POSIX shell,如果它可以在dash 中运行,那么几乎可以肯定它可以在其他 POSIX shell 中运行。

试试:

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

【讨论】:

  • 如果您在想“这里与问题中的语法有什么区别”:它使用= 而不是==
  • 在本例中如何使用通配符?我试过 if [ "$OSTYPE" = "linux"* ];然后但它没有得到linux-arm,例如......
【解决方案2】:

为什么您的脚本甚至有可能被“错误”的 shell 运行?我认为您可以通过在脚本顶部使用标准 sh-bang 行来将其作为产品的先决条件:

#!/bin/bash

即使用户使用不同的 shell,其他 shell 通常仍然存在,如果没有,只需抱怨并声明它们是 pre-req。

与特定内核级别或 awk 的存在可以作为前置请求完全相同的方式。

对于您的具体问题,我相信 shbash 都允许将单个 '=' 用于字符串比较 - 这是 POSIX 行为:

if [ "a" = "a" ] ; then
    echo yes
fi

yes

【讨论】:

  • “为什么你的脚本甚至有可能被“错误”的 shell 运行?” - 是否可以控制 Autoconf 使用哪个 shell? (这就是我寻找答案的原因)
【解决方案3】:

使用= 代替==。比较由 test(1) 处理。 /usr/bin/[ 通常是指向 /usr/bin/test 的链接。唯一的区别是,如果您在 shell 脚本中使用[,那么] 也是必需的。

请注意,bash 有一个内置的test/[,所以它实际上并没有使用/usr/bin/test

【讨论】:

  • 是否有关于内置 test 和单等号或双等号的官方规范?
【解决方案4】:

已经发布的答案肯定是正确的,但可能值得注意的是,偶尔参数扩展可以达到相同的目的,也许还有一些额外的灵活性。

% 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'

好的,所以上面的内容并不是超级有用,但也考虑到您可以使用类似的方法来测试here-documents中的变量,必要时进行内联变量分配(在一定程度上......) ,甚至只是作为一种更短(更快!)的方式来编写您的第一个语句。

[ ! "${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
%

【讨论】:

  • 我不确定我是否看到了这些技术的巨大好处,除非你想赢得一场混淆比赛。
  • 哇...我需要有人来 ELI5 :)
【解决方案5】:

你可以使用 awk

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-23
    • 2015-08-30
    • 2012-03-02
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多