如何比较Bash中的字符串

时间:2020-01-09 10:37:20  来源:igfitidea点击:

这是正常现象,或者我要说的是Linux开发人员在需要比较字符串的脚本上使用的日常用例。
但是我已经看到很多人倾向于混淆字符串和整数。
因此,在继续学习bash中的字符串比较之前,让我们了解bash和整数值之间的基本区别。

整数和字符串之间的区别

现在在bash中,我们有字符串和整数。
因此,在单引号('')或者双引号("")下提供的任何文本都被视为字符串。
因此,即使我们在单引号或者双引号下提供了一个数值,默认情况下它应为整数,但由于带引号,它将被视为字符串。

说明:

"整数"和"字符串"使用一组不同的比较运算符。

让我们举一些例子来理解bash中string和integer之间的区别:

举些例子:

VAL="text" => Here text is a string
VAL="10"   => Here 10 is a string even though this is an integer as it is provided with double quotes
VAL='11'   => Again for the same reason 11 will be considered as string as it is under single quotes
VAL=11     => Here 11 is integer so this needs separate handling for bash string comparison

字符串比较运算符

首先,让我们了解可用于bash和shell脚本中的字符串比较的不同比较运算符。

名称运算符语法单括号语法双括号语法注释
is equal to=(or) ==[ "string1" = "string2" ][[ "$string1" == "string2" ]]如果两个操作数相等,则返回TRUE
is not equal to!=[ "string1" != "string2" ][[ "string1" != "string2" ]]如果两个操作数不相等,则返回TRUE
is less than@@@[ "string1" \@@@ "string2" ][[ "string1" @@@ "string2" ]]如果右操作数被认为低于左操作数,则使用单括号中运算符的转义符

返回TRUE

比较是使用ASCII字母顺序完成的
is greater than>[ "string1" \> "string2" ][[ "string1" @@@ "string2" ]]使用单括号中运算符的转义符

如果认为右操作数高于左操作数,则返回TRUE

比较是使用ASCII字母顺序完成的
zero string length-z[ -z "string2" ][[ -z "string2" ]]如果提供的字符串长度为零,即null值,则返回TRUE
non zero length-n[ -n "string2" ][[ -n "string2" ]]如果字符串不为零,即不为空,则返回TRUE

检查字符串是否相等

Bash按长度比较字符串,每个字符匹配。
例如,在此shell脚本中,我用相同的字符串定义了两个变量

VAR1="theitroad"
VAR2="theitroad"
if [[ "$VAR1" == "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is equal to $VAR2"
else
   echo "exit status: $?"
   echo "$VAR1 is NOT equal to $VAR2"
fi

该脚本的输出显示,第一个条件返回TRUE,且退出状态为零,因此两个字符串均视为EQUAL

exit status: 0
theitroad is equal to theitroad

如果我们在DEBUG模式下运行(我最喜欢的shell脚本)

+ VAR1=theitroad
+ VAR2=theitroad
+ [[ theitroad == \g\o\l\i\n\u\x\c\l\o\u\d ]]
+ echo 'exit status: 0'
exit status: 0
+ echo 'theitroad is equal to theitroad'
theitroad is equal to theitroad

如我们所见,bash在返回TRUE状态之前比较了字符串的长度和每个字符

检查字符串是否不相等

我们将对其中一个变量进行一些更改,然后执行字符串比较

VAR1="theitroad"
VAR2="website"
if [[ "$VAR1" != "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is NOT equal to $VAR2"
fi

该脚本的输出显示第一个条件返回TRUE,且退出状态为零,因此两个字符串都不相等

exit status: 0
theitroad is NOT equal to website

使用ASCII顺序比较字符串

到目前为止,我个人还没有使用过它,我想知道我的读者是否有任何用例可以对字符串进行这种比较,所以我使用了两个带有两个不同字符串的变量

VAR1="A"
VAR2="B"
if [[ "$VAR1" > "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is greater than $VAR2"
elif [[ "$VAR1" == "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is equal to $VAR2"
else
   echo "exit status: $?"
   echo "$VAR1 is lesser than $VAR2"
fi

该脚本的输出为

exit status: 1
A is lesser than B

因为按照ASCII码,字母A具有065的ASCII码,而字母B具有066的ASCII码,所以字母A被认为比B小

说明:

如果我们使用的是大括号[],则必须在大于(>)和小于(<)符号之间使用转义符

检查字符串是否为空

这是实时生产环境中最常用的运算符之一,在该环境中,我们将某些命令的输出收集到变量中,并希望确保该变量不为空,即它能够收集命令输出

在此脚本中,我尝试获取虚拟进程的PID,因此预期该变量为空

VAR=`pidof dummy`
if [ -z "$VAR" ]; then
  echo "exit status: $?"
  echo "$VAR is null."
else
  echo "exit status: $?"
  echo "$VAR is NOT null."
  echo "value: $VAR"
fi

该脚本的输出确认我们的字符串为空并返回TRUE

exit status: 0
$VAR is null.

在此脚本中,我将寻找Java进程的PID

VAR=`pidof java`
if [ -z "$VAR" ]; then
  echo "exit status: $?"
  echo "$VAR is null."
else
  echo "exit status: $?"
  echo "$VAR is NOT null."
  echo "value: $VAR"
fi

该脚本的输出告诉我们VAR字符串不为空,并返回FALSE

exit status: 1
$VAR is NOT null.
value: 10592

检查字符串是否为非零或者非空

我们可以使用相同的脚本来验证变量是否为非零。
不同之处在于-z,当字符串无值时,退出为零;而与-n相反,如果字符串非零,则退出状态为零。

VAR=`pidof java`
if [ -n "$VAR" ]; then
  echo "exit status: $?"
  echo "$VAR is NOT null."
else
  echo "exit status: $?"
  echo "$VAR is null."
  echo "value: $VAR"
fi

脚本的输出

exit status: 0
$VAR is NOT null.

Shell脚本:字符串比较运算符示例

我们将检查一些示例以了解和学习bash字符串比较。

其中:我创建了一个脚本,该脚本将使用在while循环中了解到的所有bash字符串比较运算符,因此我不必编写单独的函数来演示示例。
除非我手动向脚本发送中断信号,否则此循环将继续运行:

# cat /tmp/bash_compare_strings.sh
#!/bin/bash
# Bash Compare Strings
# Run the script untill manually interrupted
while true; do
   # Collect VAR1 and VAR2 value from end user
   read -r -p "Enter VAR1 value: " VAR1
   read -r -p "Enter VAR1 value: " VAR2
   # Check if $VAR1 value is less that $VAR2
   if [[ "$VAR1" < "$VAR2" ]];then 
      echo "$VAR1 is less than $VAR2" 
   # Check if $VAR1 value is greater than $VAR2 
   elif [[ "$VAR1" > "$VAR2" ]];then
      echo "$VAR1 is greater than $VAR2"
   # Check if $VAR1 is equal to $VAR2	  
   elif [[ "$VAR1" == "$VAR2" ]];then
      echo "$VAR1 is equal to $VAR2"
   # Chcek if $VAR1 is not equal to $VAR2	  
   elif [[ "$VAR1" != "$VAR2" ]];then
      echo "$VAR1 is NOT equal to $VAR2"
   else
   # If none of the above condition matches
      echo "Unable to get the status"
  fi
done

现在,我们将在此脚本中为VAR1和VAR2提供不同的值,并检查退出状态。
如果我们观察到我将两个变量都放在了双引号下,那么即使我们将数字作为此脚本的输入,它们也将被视为字符串。

提供脚本的可执行权限

# chmod u+x /tmp/bash_compare_strings.sh

让我们执行脚本以了解有关bash比较字符串运算符的更多信息:

# /tmp/bash_compare_strings.sh
Enter VAR1 value: hynman
Enter VAR1 value: hynman
hynman is equal to hynman        <- We know both the strings are same
Enter VAR1 value: hynman
Enter VAR1 value: amit
hynman is greater than amit      <- hynman has more number of char compared to amit
Enter VAR1 value: amit
Enter VAR1 value: hynman
amit is less than hynman         <- amit has less number of char compared to hynman
Enter VAR1 value: 100
Enter VAR1 value: 100
100 is equal to 100              <- both the strings are same
Enter VAR1 value: deep100
Enter VAR1 value: deep101
deep100 is less than deep101     <- we have combined text with number. deep is same in both variables but 100 is less than 101
Enter VAR1 value: deep100
Enter VAR1 value: amit101
deep100 is greater than amit101  <- This depends on the combination of ASCII code value

对字符串执行正则表达式和模式(=~)匹配

我们将检查更多示例以比较bash regex匹配和bash模式匹配。
其中:我编写了一个线性脚本来检查bash regex匹配和bash模式匹配。

[root@controller ~]# [[ "my name is hynman prasad" =~ "prasad"$]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

我们还可以将其分解为多行脚本,新手将更容易理解

if [[ "my name is hynman prasad" =~ "prasad"$]]; then
   echo "bash regex match"
else
   echo "bash regex nomatch"   
fi

这里我们使用=~而不是==来匹配一个模式,并使用美元$符号来匹配字符串的最后一个单词。
现在,由于prasad是"我的名字是hynman prasad"中的最后一个单词,因此bash模式匹配成功。

同样,我在字符串中使用" ^"检查起始词,因为" my"是"我的名字是hynman prasad"中的起始词,因此bash模式匹配成功。

[root@controller ~]# [[ "my name is hynman prasad" =~ ^"my" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

我们还可以在没有任何正则表达式的情况下查找字符串中的某些单词,如下所示。
由于"我的名字是hynman prasad"中出现了" hynman"字样,因此bash模式匹配成功

[root@controller ~]# [[ "my name is hynman prasad" =~ "hynman" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

默认情况下,如果我们在下面的检查中使用等于,那么它会说nomatch,因为与==一样,shell会尝试对两个变量进行字符匹配,因为检查失败

[root@controller ~]# [[ "my name is hynman prasad" == "hynman" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex nomatch

因此,我们使用通配符(*)来匹配字符串,以忽略开始和结束文本,bash regex匹配成功。

[root@controller ~]# [[ "my name is hynman prasad" == *"hynman"* ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match