shell脚本中字符串的不区分大小写比较

Sac*_*iya 117 string shell compare case-insensitive

==运算符用于比较的shell脚本两个字符串.但是,我想比较两个忽略大小写的字符串,怎么做呢?这有什么标准命令吗?

小智 137

在Bash中,您可以使用参数扩展将字符串修改为所有低/大写:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
Run Code Online (Sandbox Code Playgroud)

  • 这是Bash 4中的新功能吗?至少在Bash 3.2.51(用于OS X 10.9)中它不起作用 - 第一个`echo`语句导致:`-bash:$ {var1 ,,}:bad substitution` (34认同)
  • 至少答复并不意味着购物选项.因此,您可以比较两个字符串忽略大小写并在同一测试中,将两个其他大小写进行比较.谢谢 (13认同)
  • @Ohad Schneider,让土耳其人担心土耳其本地化问题,我只需要一种快速有效的方式进行字符串匹配,这需要用huuuuuge margin来获取蛋糕 (5认同)
  • `,,` 和 `^^` 在 `bash 4.4.20` 中都可以工作,但在 `zsh 5.4.2` 中都不起作用 (ubuntu 18.04) (3认同)
  • 这种不区分大小写的比较实现很容易出现本地化问题(例如土耳其语 I 问题)。我不知道“shopt -s nocasematch”是如何实现的,但通常这种“语言级”解决方案可以正确处理它。 (2认同)

Rio*_*iot 100

所有这些答案都忽略了最简单快捷的方法(只要你有Bash 4):

if [ "${var1,,}" = "${var2,,}" ]; then
  echo ":)"
fi
Run Code Online (Sandbox Code Playgroud)

你所做的就是将两个字符串转换为小写并比较结果.

  • @ d4Rk这就是为什么我的回答的第一句话说"只要你有Bash 4".话虽如此,Bash 4在撰写此评论时已经出了七年多了,我自己的OS X安装已经有了这么长时间. (7认同)
  • 这仅适用于Bash 4或更高版本(例如,不适用于Mac OS X 10.11) (4认同)
  • @ d4Rk这是可以理解的 - 如果你真的需要保证可移植性,我建议坚持使用POSIX shell标准,因为在某些情况下你根本不能保证找到任何版本的bash. (2认同)

gho*_*g74 66

如果你有bash

str1="MATCH"
str2="match"
shopt -s nocasematch
case "$str1" in
 $str2 ) echo "match";;
 *) echo "no match";;
esac
Run Code Online (Sandbox Code Playgroud)

否则,你应该告诉我们你正在使用什么样的外壳.

替代方案,使用awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'
Run Code Online (Sandbox Code Playgroud)

  • 对于任何使用`if`语句比较字符串的人来说,`shopt`方法要求你使用双括号`[[]]`形式的条件而不是单括号`[]`形式.另见:http://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html (31认同)
  • 在比较完成后执行`shopt -u nocasematch`可能是明智的,以便恢复到bash的默认值. (7认同)
  • 最好保存并恢复`nocasematch`设置.用`SHELLNOCASEMATCH = \`shopt -p nocasematch \``抓住它然后用`shopt -s nocasematch`改变它,一旦完成,用`$ SHELLNOCASEMATCH恢复它 (5认同)
  • 问题表明`==`用于比较两个字符串,但响应使用`case`语句演示了不区分大小写的比较.令人欣慰的是,`shopt`解决方案还可以使用`==`,`= ~`和其他字符串比较运算符不区分大小写. (3认同)
  • 更妙的是:`SHELLNOCASEMATCH = $(shopt -p nocasematch; true)`,因为如果未设置该选项,`shopt -p`将以代码1退出,如果`set -e`被设置,这可能导致脚本中止。有效。 (2认同)

小智 35

与ghostdog74的回答相同但代码略有不同

shopt -s nocasematch
[[ "foo" == "Foo" ]] && echo "match" || echo "notmatch"
shopt -u nocasematch
Run Code Online (Sandbox Code Playgroud)

  • 很好,因为`case`陈述(包括那些在ghostdog的答案中)将永远让我的皮肤爬行 (3认同)

Ran*_*tor 13

一种方法是将两个字符串转换为上限或下限:

test $(echo "string" | /bin/tr '[:upper:]' '[:lower:]') = $(echo "String" | /bin/tr '[:upper:]' '[:lower:]') && echo same || echo different
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用grep:

echo "string" | grep -qi '^String$' && echo same || echo different
Run Code Online (Sandbox Code Playgroud)


小智 10

我发现了这个很棒的博客/教程/有关处理区分大小写模式的内容。下面通过例子对三种方法进行详细说明:

1.使用tr命令将模式转换为小写

opt=$( tr '[:upper:]' '[:lower:]' <<<"$1" )
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other options"
                ;;
esac
Run Code Online (Sandbox Code Playgroud)

2.谨慎使用 case 模式的通配符

opt=$1
case $opt in
        [Ss][Qq][Ll])
                echo "Running mysql backup using mysqldump tool..."
                ;;
        [Ss][Yy][Nn][Cc])
                echo "Running backup using rsync tool..."
                ;;
        [Tt][Aa][Rr])
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac
Run Code Online (Sandbox Code Playgroud)

3.开启nocasematch

opt=$1
shopt -s nocasematch
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

shopt -u nocasematch
Run Code Online (Sandbox Code Playgroud)


小智 7

对于korn shell,我使用了排版内置命令(-l表示小写,-u表示大写).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi
Run Code Online (Sandbox Code Playgroud)

  • 就性能而言,这比启动awk或任何其他进程更好. (2认同)

小智 5

如果您使用fgrep进行不区分大小写的行比较,则非常简单:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi
Run Code Online (Sandbox Code Playgroud)


sma*_*c89 5

因为zsh语法略有不同,但仍然比这里的大多数答案短:

> str1='mAtCh'
> str2='MaTcH'
> [[ "$str1:u" = "$str2:u" ]] && echo 'Strings Match!'
Strings Match!
>
Run Code Online (Sandbox Code Playgroud)

这将在比较之前将两个字符串都转换为大写。


另一种方法使用 zsh's globbing flags,它允许我们通过使用iglob 标志直接使用不区分大小写的匹配:

setopt extendedglob
[[ $str1 = (#i)$str2 ]] && echo "Match success"
[[ $str1 = (#i)match ]] && echo "Match success"
Run Code Online (Sandbox Code Playgroud)