在shell脚本中不区分大小写的子字符串搜索


22

我该如何编写一个shell脚本来对命令输出进行不区分大小写的子字符串匹配?


grep -i也许?
拉梅什

如何将其放入脚本中?如果这是新手问题,很抱歉。我刚刚开始学习Linux,因为我需要实习。谢谢!
米格尔·罗克

1
您要问的是Shell脚本 -“ Linux”不是一种编程语言,它是一个操作系统内核。linux最常使用的shell bashunix标准sh的超集。您可能首先查看以下内容之一:| 1 | | 2 | -只是为了掌握实际情况。
goldilocks

1
现在,这个问题看起来很清楚,并且与帮助中心中的指南相符。可以为他人的利益打开吗?
BobDoolittle 2014年

2
我不明白为什么这个问题不清楚。我应该添加些什么使其清晰?
Miguel Roque 2014年

Answers:


11

首先,这是一个不忽略大小写的简单示例脚本:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

尝试更改右侧的字符串hello,它不再应该echo it works。尝试用echo hello您选择的命令替换。如果要忽略大小写,并且两个字符串都不包含换行符,则可以使用grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

此处的关键是您要将命令输出传递给grep。该if语句测试管道中最右边命令的退出状态-在本例中为grep。当且仅当找到匹配项时,Grep成功退出。

-igrep的选项的说,忽略大小写。
-q选项表示在第一个匹配项后不发出输出并退出。
-F选项表示将参数视为字符串而不是正则表达式。

注意,第一个示例使用允许直接比较和各种有用的运算符。第二种形式只是执行命令并测试其退出状态。[ expression ]


我不明白为什么Gilles觉得有必要更改我贡献的代码。他没有破坏任何东西,但是一切正常。在此示例中,您不需要双引号-但是,如果输出中包含空格,则双引号很重要。==和=一样有效,因为sh实际上在Linux上是bash。原始的Bourne Shell在此刻早已消失。我不认为Solaris也不会发布它。尽管在此示例中没有必要,但我同意双引号可能是最佳做法,但我认为'=='也是这样,以使分配和比较清楚地分开。
BobDoolittle

等一下,这样一个人可以编辑帖子吗?我不知道。
米格尔·罗克

有足够的声誉,是的。我希望声誉很高的人在进行不必要的编辑之前会三思而后行,尤其是在该论坛中进行编码。unix.stackexchange.com/help/privileges
BobDoolittle 2014年

@BobDoolittle在某些情况下可能会有所不同,但与您的设置无关-很好知道。

2
请注意,实际上,这不仅与Bourne Shell有关。==不是POSIX。sh并非bash在所有基于Linux的系统上。==不支持ashsh至少基于BSD和Debian衍生工具中的BSD的基础)或posh,并且不支持zsh。没有必要加倍=[是用于测试的命令。这里没有必要在赋值和比较之间进行歧义。那是不同的(( a == b ))(( a = b))。使用==在开头的脚本#! /bin/sh是错误的。如果采用假设kshbash语法,请相应地更新#!
斯特凡Chazelas

49

如果设置了shell选项bash,则可以使用regex运算符进行不区分大小写的子字符串匹配。例如=~nocasematch

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match

6
大声笑!难懂的外壳知识点。
BobDoolittle 2014年

2
此选项还会影响简单匹配运算符。[[ XYZ == xyz ]] && echo "match"=>match
itsadok

7

对于区分大小写的字符串,在变量needle的值中搜索变量的值haystack

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

对于不区分大小写的字符串搜索,请将两者都转换为相同的大小写。

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

注意,tr在GNU coreutils中不支持多字节语言环境(例如UTF-8)。要使用多字节语言环境,请改用awk。如果要使用awk,则可以使其进行字符串比较,而不仅仅是转换。

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

tr从BusyBox的不支持的语法; 您可以改用。BusyBox不支持非ASCII语言环境。[:CLASS:]tr a-z A-Z

在bash(但不是sh)的4.0+版本中,提供了用于大小写转换的内置语法和用于字符串匹配的简单语法。

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac

我意识到这已经有几岁了,但是所有这些printf | tr使我的头转了转。在可能的情况下,尽量减少对命令的调用...给定变量v,您可以使用完成相同的操作v=$(tr '[:lower:]' '[:upper:]' <<<$v)。对于以前从未看过的人来说,<<<本质上是一个“ here变量”,就像在<<EOFhere文档中使用一样。不需要printfecho除非您绝对必须这样做。
威尔

@Will仅在具有以下<<<运算符的shell中起作用:ksh,bash,zsh,但不包括普通sh。就printf其运行方式而言,它与管道非常接近:对fork和的调用次数相同execve(假设它printf是内置的,在大多数常见的shell中就是这种情况);区别在于<<<创建临时文件而不是使用管道。<<<方便键入但不改善性能。
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.