如何在Bash中比较字符串


Answers:


1371

在if语句中使用变量

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

如果您想在不匹配的地方做某事,请替换=!=。您可以在各自的文档中阅读有关字符串运算算术运算的更多信息。

为什么我们在周围使用引号$x

您希望用引号引起来$x,因为如果为空,则Bash脚本会遇到语法错误,如下所示:

if [ = "valid" ]; then

非标准使用==运算符

请注意,Bash允许==用于与相等[,但这不是标准的

使用第一种情况,其中引号$x是可选的:

if [[ "$x" == "valid" ]]; then

或使用第二种情况:

if [ "$x" = "valid" ]; then

12
这与意外的操作员错误中给出的可接受答案有何关系?使用时出现相同的错误[ "$1" == "on" ]。将其更改为[“ $ 1” =“ on”]解决了该问题。
Piotr Dobrogost

78
需要空格。
TAAPSogeking

6
@JohnFeminella用bash脚本编写时,它应该只有一个=而不是两个。
user13107 2014年

72
可能值得注意的是您无法使用[ $x -eq "valid" ]-eq是整数而不是字符串的比较运算符。
craq 2015年

2
@Alex,在哪种情况下(如果有的话)我需要使用pattern ["x$yes" == "xyes"],即在变量和字符串文字前都加上一个前缀x吗?那是古老的遗迹吗?还是在某些情况下真的需要吗?
lanoxx

141

或者,如果您不需要else子句:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

70
而且,如果您确实需要else子句并想做一个疯狂的单行代码:[“ $ x” ==“ valid”] && echo“ valid” || 回声“无效”
马特·怀特

11
@MattWhite:这通常是一个坏主意,echo可能会失败。
gniourf_gniourf

1
甚至出现了可能出现的陷阱,来自marko && MattWhite的美丽而优雅的方式
Deko,

3
@gniourf_gniourf,没问题,请使用 [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid"
12431234123412341234123

4
@ 12431234123412341234123 { echo invalid && false; }比效率更高( echo invalid && false ),因为它避免为不必要的subshel​​l付费。
查尔斯·达菲

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

笔记:

  1. 之间的空间if[]是重要的
  2. ><是重定向操作符,因此分别使用\>和对其进行转义\<

6
感谢您的字符串字母顺序比较
shadi

我的问题是$a实际上将其" "括起来作为字符串文字值的一部分,因此我不得不使用转义字符$b来比较这些值。我可以在运行后找到它bash -x ./script.sh,-x标志使您可以查看每次执行的值并有助于调试。
ShahNewazKhan

请注意,字母顺序比较不是POSIX标准化的,因此不能保证它可以在非GNU平台/非bash shell上使用。仅保证pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html上的操作可移植。
查尔斯·达菲

62

要将字符串与通配符进行比较,请使用

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
通配符只能在右侧使用,这一点很重要!还要注意"通配符周围的缺失。(顺便说一句:通配符+1!)
Scz

6
扩展$stringB 必须被引用(并且,顺便说一句,左侧不需要加引号)if [[ $stringA = *"$stringB"* ]]; then
gniourf_gniourf

我试图对文件路径中的文件名使用相同的通配符逻辑。但这对我不起作用。尝试了此处提供的所有不同通配符字符串。但总会出现其他情况。在我的情况下,stringA是文件路径/ tmp / file,而stringB是“文件”。
下雨

35

我必须不同意其中一项评论:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

不,那不是疯子

只是看起来好像是一个未开始的人...

它以某种方式使用通用模式作为语言。

在您学习了语言之后。

其实很高兴读

这是一个简单的逻辑表达式,有一个特殊部分:逻辑运算符的惰性求值。

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

每个部分都是一个逻辑表达式;第一个可能为true或false,其他两个始终为true。

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

现在,在评估时,将检查第一个。如果为假,则与逻辑的第二个操作数 &&之后的那个无关。第一个是不正确的,因此无论如何它不能是第一个和第二个都是正确的。
现在,在这种情况下,逻辑的第一面为 false || false,但如果另一面(第三部分)为true,则可能为true。

因此,将对第三部分进行评估-主要是将消息写为副作用。(其结果0为true,在此不使用)

其他情况相似,但更简单-而且-我保证!是-可以-易于阅读!
(我没有,但是我认为拥有灰胡子的UNIX老手对此很有帮助。)


17
... && ... || ...通常时(对不起樽Unix的老将,你已经错了这么长的时间),皱眉,因为它不是语义上等同于if ... then ... else ...。别担心,这是一个常见的陷阱
gniourf_gniourf

6
@gniourf_gniourf OP没错-正如您建议的那样,它们也不可能是无知的。 ... && ... || ...是一个完全有效的模式,也是一个常见的bash习语。它的使用确实规定了先验知识(如果听众中有初学者,可能要记住这些知识),但是OP有能力证明他们知道如何避免开放的人孔盖。
ebpa

3
@ebpa如果&&后面的语句返回false值,将执行||后面的语句怎么办??如果是这样,那是错误的,也许是gniourf的建议
TSG

4
我以为echo只是一个例子。&&之后的语句可能仍返回非零值
TSG

2
@gniourf_gniourf +1,用于发布指向Bash Pitfalls的链接!很有用!
美洲虎

21

您还可以使用用例/ esac

case "$string" in
 "$pattern" ) echo "found";;
esac

是等价的还是包含的?
ytpillai

@ytpillai,它是等效的。请记住|,在之前,您可以将模式分开)。该in语句等效于thenin if语句。您可能会争辩说它适用于一系列模式,如果您来自Python,则每个列表都有其自己的操作声明。不喜欢substring in string,而是for item in list*如果需要else条件,请使用a 作为最后一个语句。它在第一次遇到时返回。
mazunki

18

以下脚本逐行从名为“ testonthis”的文件中读取内容,然后将每行与一个简单字符串,一个带特殊字符的字符串和一个正则表达式进行比较。如果不匹配,则脚本将打印该行,否则不打印。

Bash中的空间非常重要。因此,以下将起作用:

[ "$LINE" != "table_name" ] 

但是以下内容不会:

["$LINE" != "table_name"] 

因此,请按原样使用:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

使用这种方法来浏览文件。也就是说,除其他外,删除UUoC。
fedorqui'SO停止伤害

这并不重要,bash因为[它实际上是一个外部二进制文件(例如,which [产生类似的结果/usr/bin/[
Patrick Bergner,

11

如果输入只有几个有效条目,我可能会使用regexp匹配项。例如,只有“开始”和“停止”是有效的动作。

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

请注意,我$ACTION使用双逗号将变量小写。还要注意,这对于太老的bash版本不起作用。


9

Bash 4+示例。注意:如果单词包含空格等,不使用引号会引起问题。请始终在IMO的Bash中引用。

以下是Bash 4+中的一些示例:

示例1,检查字符串中的“是”(不区分大小写):

    if [[ "${str,,}" == *"yes"* ]] ;then

示例2,检查字符串中的“是”(不区分大小写):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

示例3,检查字符串中的“是”(区分大小写):

     if [[ "${str}" == *"yes"* ]] ;then

示例4,检查字符串中的“是”(区分大小写):

     if [[ "${str}" =~ "yes" ]] ;then

示例5,完全匹配(区分大小写):

     if [[ "${str}" == "yes" ]] ;then

示例6,完全匹配(不区分大小写):

     if [[ "${str,,}" == "yes" ]] ;then

示例7,完全匹配:

     if [ "$a" = "$b" ] ;then

请享用。


对我来说(mac GNU bash版本4.4.12(1)-发行版x86_64-apple-darwin17.0.0),我必须使用if [ "$a"="$b" ]或者它不起作用...等号周围不能有空格
频谱

1

我这样做是与Bash和Dash(sh)兼容的:

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

使用前面的(和不使用前面的有什么区别?
mazunki
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.