【发布时间】:2009-11-13 11:31:51
【问题描述】:
== 运算符用于比较 shell 脚本中的两个字符串。但是,我想比较两个字符串忽略大小写,怎么办?有什么标准的命令吗?
【问题讨论】:
-
快速说明:不,
==不是 shell 中的标准字符串比较运算符;唯一符合 POSIX 标准的比较运算符是=。
标签: string shell compare case-insensitive
== 运算符用于比较 shell 脚本中的两个字符串。但是,我想比较两个字符串忽略大小写,怎么办?有什么标准的命令吗?
【问题讨论】:
== 不是 shell 中的标准字符串比较运算符;唯一符合 POSIX 标准的比较运算符是 =。
标签: string shell compare case-insensitive
在 Bash 中,您可以使用参数扩展将字符串修改为全部小写/大写:
var1=TesT
var2=tEst
echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
【讨论】:
echo 语句导致:-bash: ${var1,,}: bad substitution
shopt -s nocasematch 是如何实现的,但通常这种“语言级”解决方案可以正确处理它。
,, 和 ^^ 在 bash 4.4.20 中工作,但在 zsh 5.4.2 (ubuntu 18.04) 中均不工作
所有这些答案都忽略了最简单快捷的方法(只要你有 Bash 4):
if [ "${var1,,}" = "${var2,,}" ]; then
echo ":)"
fi
您所做的只是将两个字符串都转换为小写并比较结果。
【讨论】:
如果你有 bash
str1="MATCH"
str2="match"
shopt -s nocasematch
case "$str1" in
$str2 ) echo "match";;
*) echo "no match";;
esac
否则,您应该告诉我们您使用的是什么外壳。
替代方案,使用 awk
str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
if ( tolower(s1) == tolower(s2) ){
print "match"
}
}'
【讨论】:
if 语句比较字符串的人,shopt 方法要求您使用双括号 [[ ]] 条件形式而不是单括号 [ ] 形式。另见:gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
== 用于比较两个字符串,但响应显示使用case 语句进行不区分大小写的比较。令人欣慰的是,shopt 解决方案还可以不区分大小写地使用 ==、=~ 和其他字符串比较运算符。
shopt -u nocasematch 以恢复到 bash 的默认值可能是明智的。
nocasematch设置。用SHELLNOCASEMATCH=`shopt -p nocasematch` 抓取它,然后用shopt -s nocasematch 更改它,一旦完成,用$SHELLNOCASEMATCH 恢复它
SHELLNOCASEMATCH=$(shopt -p nocasematch; true),因为如果未设置该选项,shopt -p 将以代码 1 退出,如果set -e 生效,这可能会导致脚本中止。
保存nocasematch 的状态(以防某些其他功能依赖于它被禁用):
local orig_nocasematch=$(shopt -p nocasematch; true)
shopt -s nocasematch
[[ "foo" == "Foo" ]] && echo "match" || echo "notmatch"
$orig_nocasematch
注意
local仅在函数内部是必需的。
此外,; true部分将在set -e开启且$(shopt -p nocasematch)失败时阻止 shell 退出(因为根本没有设置 nocasematch)。
【讨论】:
case 声明(包括ghostdog 的回答中的那些)总是会让我的皮肤爬行
case 符合 POSIX 标准; [[ ]] 是非标准扩展。从可移植性的角度来看,case 是可行的方法。
一种方法是将两个字符串都转换为大写或小写:
test $(echo "string" | /bin/tr '[:upper:]' '[:lower:]') = $(echo "String" | /bin/tr '[:upper:]' '[:lower:]') && echo same || echo different
另一种方法是使用 grep:
echo "string" | grep -qi '^String$' && echo same || echo different
【讨论】:
tr 方法(通过busybox 提供sh)。谢谢。
test "$(...)" = "$(...)" -- 对于所有可能的字符串的正确操作,双引号不是可选的。
对于 korn shell,我使用 typeset 内置命令(-l 表示小写,-u 表示大写)。
var=True
typeset -l var
if [[ $var == "true" ]]; then
print "match"
fi
【讨论】:
如果您使用 fgrep 进行不区分大小写的行比较,则非常容易:
str1="MATCH"
str2="match"
if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
echo "case-insensitive match";
fi
【讨论】:
if fgrep -qix -- "$str1" <<<"$str2"; then会更好。
zsh 的语法略有不同,但仍比这里的大多数答案短:
> str1='mAtCh'
> str2='MaTcH'
> [[ "$str1:u" = "$str2:u" ]] && echo 'Strings Match!'
Strings Match!
>
这将在比较之前将两个字符串都转换为大写。
另一种方法是使用 zsh 的globbing flags,它允许我们通过使用i glob 标志直接使用不区分大小写的匹配:
setopt extendedglob
[[ $str1 = (#i)$str2 ]] && echo "Match success"
# this example compares the variable with a literal string 'match'
[[ $str1 = (#i)match ]] && echo "Match success"
【讨论】:
globbing flags 比较 str1 以匹配?
我遇到了这个很棒的博客/教程/关于dealing with case sensitive pattern 的任何内容。以下三种方法通过实例进行详细说明:
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
2.谨慎使用大小写模式
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
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
【讨论】:
这是我使用 tr 的解决方案:
var1=match
var2=MATCH
var1=`echo $var1 | tr '[A-Z]' '[a-z]'`
var2=`echo $var2 | tr '[A-Z]' '[a-z]'`
if [ "$var1" = "$var2" ] ; then
echo "MATCH"
fi
【讨论】:
echo $var 需要引号 -- echo "$var",或者如果var1='hello * world' 在操作后您的var1 中会有一个文件名列表,即使它不包含这样的列表之前。
grep 有一个 -i 标志,表示不区分大小写,因此请它告诉您 var2 是否在 var1 中。
var1=match
var2=MATCH
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
echo "MATCH"
fi
【讨论】:
在类 Unix 操作系统上,test 命令检查文件类型并比较值。
str1="MATCH"
str2="match"
if test $str1 = $str2
then
echo "equal yes"
else
echo "equal not"
fi
在类 Unix 操作系统上,test 命令检查文件类型并比较值。
这样很简单。
几行代码
【讨论】:
test "$str1" = "$str2" -- 引号对于可靠的正确操作不是可选的。
shopt -s nocaseglob
【讨论】:
“tr”实用程序(翻译字符)始终存在于所有 Unix/Linux 机器上,并且是轻量级的。
这是一个可用于处理不区分大小写比较的函数。由于 'tr' 的确切位置可能不同,我们首先探测其可能的位置并将正确的位置存储在适当命名为“BIN_TR”的环境变量中。
declare BIN_TR=$( ls /bin/tr /usr/bin/tr 2>/dev/null | head -1 );
然后在函数声明中使用。
toLowerCase() {
echo "$*" | $BIN_TR '[:upper:]' '[:lower:]'
}
使用“tr”的解决方案预计在不同的操作系统和操作系统设置变体之间具有高度可移植性。虽然 'awk' 也很有可能,但与 'awk' 相比,'tr' 实用程序很小,因此使用 'tr' 的函数可能更轻。
【讨论】:
... | $BIN_TR 而不仅仅是... | tr? shell 本身会自动进行 PATH 查找并缓存该查找——它的内置查找比使用 ls 的 hack 更有效。
/bin 或/usr/bin。我在 NixOS 机器上写这个;我的tr 副本来自/run/current-system/sw/bin/tr,它是/nix/store/cc4nnlspm4pwmp5rvjl6wpy9nyzcsbnr-coreutils-8.31/bin/tr 的符号链接。