Shell中的条件测试和判断语句

条件测试

为了能够正确处理Shell程序运行过程中遇到的各种情况,Linux Shell提供了一组测试运算符。通过这些运算符,Shell程序能够判断某种或者几个条件是否成立。条件测试在各种流程控制语句,例如判断语句和循环语句中发挥了重要的作用,所以,了解和掌握这些条件测试是非常重要的。

基本语法

在Shell程序中,用户可以使用测试语句来测试指定的条件表达式的条件的真或者假。当指定的条件为真时,整个条件测试的返回值为0;反之,如果指定的条件为假,则条件测试语句的返回值为非0值。
条件测试的语法有2种,分别是test命令和[命令,test命令的语法如下:
test expression
其中,参数expression表示需要进行测试的条件表达式,可以由字符串、整数、文件名以及各种运算符组成。例如,下面的表达式都是有效的条件表达式:

1 -eq 2		//判断1是否等于2
‘string’		//永真
-z ‘string’
-e file		//判断文件是否为空
[命令的语法如下:
[ expression ]

在上面的语法中,[是条件测试命令,参数expression是一个条件表达式。其中expression的语法与上面的test命令中的语法完全相同。条件表达式和左右方括号之间都必须有一个空格。

字符串测试

通常情况下,对于字符串的操作主要包括判断字符串变量是否为空以及两个字符串是否相等。在Shell中,用户可以通过5种运算符来对字符串进行操作。

运算符 说明
string 判断指定字符串是否为空
string1=string2 判断2个字符串string1和string2是否相等
strig1!=string2 判断2个字符串string1和string2是否不相等
-n string 判断string是否是非空串
-z string 判断string是否是空串

【例4-1】演示字符串测试的使用方法

#定义字符串变量
[root@localhost chapter4]# a="abc"
#使用test命令测试变量$a是否为空串
[root@localhost chapter4]# test $a
#通过echo命令和$?环境变量输出测试结果
[root@localhost chapter4]# echo $?
#输出结果为0,表示变量$a的值不为空
0
#使用-n运算符测试变量$a是否不为空
[root@localhost chapter4]# test -n "$a"
#输出测试结果
[root@localhost chapter4]# echo $?
#测试结果为0表示变量为非空字符串
0
#使用-z运算符测试变量$a是否为空串
[root@localhost chapter4]# test -z "$a"
#测试结果为1,表示变量$a不是空串
[root@localhost chapter4]# echo $?
1

【例4-2】演示Shell中比较2个字符串值的方法

#定义变量$a
[root@localhost chapter4]# a="hello"
#定义变量$b
[root@localhost chapter4]# b="world"
#比较2个字符串是否相等
[root@localhost chapter4]# [ "$a" = "$b" ]
#输出测试结果为1,表示$a和$b不相等
[root@localhost chapter4]# echo $?
1
#测试$a和$b是否不相等
[root@localhost chapter4]# test "$a" != "$b"
#输出测试结果为0,表示$a和$b不相等
[root@localhost chapter4]# echo $?
0

【例4-3】说明空格对于字符串比较结果的影响

#定义字符串变量$a
[root@localhost chapter4]# a="Hello      world. "
#定义字符串变量$b
[root@localhost chapter4]# b="Hello world."
#测试$a和$b是否相等
[root@localhost chapter4]# [ "$a" = "$b" ]
[root@localhost chapter4]# echo $?
1

【例4-4】演示字母大小写对于字符串比较结果的影响

#变量$a的第1个字母为大写的H
[root@localhost chapter4]# a="Hello world."
#变量$b的第1个字母为小写的h
[root@localhost chapter4]# b="hello world."
[root@localhost chapter4]# [ "$a" = "$b" ]
#变量$a和$b的值不相等
[root@localhost chapter4]# echo $?
1

整数测试

与字符串测试类似,整数测试也有2种形式的语法:
test number1 op number2
或者
[ number1 op number2 ]
其中,number1和number2分别表示参与比较的2个整数,可以是常量或者变量。op表示运算符。

运算符 说明
number1 -eq number2 比较number1是否等于number2。如果相等,测试结果为0
number1 -ne number2 比较number1和number2是否不相等。如果number1和number2不相等,测试结果为0
number1 -gt number2 比较number1是否大于number2。如果number1大于number2,测试结果为0
number1 -lt number2 比较number1是否小于number2。如果number1小于number2,测试结果为0
number1 -ge number2 试number1是否大于等于number2。如果number1大于等于number2,测试结果为0
number1 -le number2 试number1是否小于等于number2。如果number1小于等于number2,测试结果为0

【例4-5】比较2个整数是否相等

[root@localhost chapter4]# [ 12 -eq 14 ]
[root@localhost chapter4]# echo $?
1

【例4-6】比较2个整数的大小

[root@localhost chapter4]# test 12 -gt 14
[root@localhost chapter4]# echo $?
1
[root@localhost chapter4]# test 12 -lt 14
[root@localhost chapter4]# echo $?
0

【例4-7】比较变量与常数的大小

[root@localhost chapter4]# x=365
[root@localhost chapter4]# test "$x" -eq 365
[root@localhost chapter4]# echo $?
0
[root@localhost chapter4]# test "$x" -gt 364
[root@localhost chapter4]# echo $?
0

【例4-8】比较2个变量值的大小。在本例中,首先定义2个整数变量$x和$y,然后判断变量$x是否小于或者等于变量$y。

[root@localhost chapter4]# x=123
[root@localhost chapter4]# y=36
[root@localhost chapter4]# [ "$x" -le "$y" ]
[root@localhost chapter4]# echo $?
1

【例4-9】使用=比较两个整数会导致错误结果。

[root@localhost chapter4]# [ 12 = 13 ]
[root@localhost chapter4]# echo $?
1
[root@localhost chapter4]# [ 12 -eq 13 ]
[root@localhost chapter4]# echo $?
1

【例4-10】使用针对整数的运算符来比较非整数会导致错误结果。

[root@localhost chapter4]# x=12.3
[root@localhost chapter4]# y=12
[root@localhost chapter4]# [ "$x" -gt "$y" ]
-bash: [: 12.3: integer expression expected

文件测试

文件测试的语法如下:
test op file
或者
[ op file ]
在上面的语法中,op表示操作符,常用的操作符参见表4.3,其中file表示要测试的文件名。
Shell中的条件测试和判断语句_第1张图片
【例4-11】通过文件操作符来判断文件是否存在

[root@localhost chapter4]# test -a file1
[root@localhost chapter4]# echo $?
0

【例4-12】判断文件是否存在。

[root@localhost chapter4]# [ -a file3 ]
[root@localhost chapter4]# echo $?
1

【例4-13】通过操作符判断各种文件类型

[root@localhost chapter4]# test -d dir1
[root@localhost chapter4]# echo $?
0
[root@localhost chapter4]# test -f file1
[root@localhost chapter4]# echo $?
08   0
[root@localhost chapter4]# test -s file2
[root@localhost chapter4]# echo $?
1
[root@localhost chapter4]# test -b file1
[root@localhost chapter4]# echo $?
1
[root@localhost chapter4]# test -b /dev/sda
[root@localhost chapter4]# echo $?
0
[root@localhost chapter4]# test -c /dev/tty
[root@localhost chapter4]# echo $?
0   

【例4-14】通过文件测试判断用户对文件的访问权限

[root@localhost chapter4]# test -w file1
[root@localhost chapter4]# echo $?
0
[root@localhost chapter4]# test -r file1
[root@localhost chapter4]# echo $?
0
[root@localhost chapter4]# test -x file1
[root@localhost chapter4]# echo $?
1
[root@localhost chapter4]# test -x hello.sh
[root@localhost chapter4]# echo $?
0

【例4-15】使用chmod命令为hello.sh文件设置setuid权限,这样的话执行该文件的用户就会临时用户该文件所有者的权限

[root@localhost chapter4]# chmod u+s hello.sh 
[root@localhost chapter4]# ll
total 12
drwxr-xr-x 	2 	root	root 	4096 	Nov  9 14:50 	dir1
-rw-r--r-- 			root	root   	12 	Nov  9 14:49 	file1
-rw-r--r-- 		1 	root 	root    	0 	Nov  9 14:49 	file2
-rwsr-xr-x 	1 	root 	root   	30 	Nov  9 15:06 	hello.sh
[root@localhost chapter4]# test -u hello.sh 
[root@localhost chapter4]# echo $?
0

逻辑操作符

Shell中的逻辑操作符可以将多个不同的条件组合起来,从而构成一个复杂的条件表达式。
Shell中的条件测试和判断语句_第2张图片
【例4-16】判断整数变量$a的值是否大于20,并且小于60。

[root@localhost chapter4]# a=35
[root@localhost chapter4]# test "$a" -gt 20 -a "$a" -lt 60	//a既大于20且a小于60
[root@localhost chapter4]# echo $?
0

【例4-17】通过条件测试来判断当前用户是否拥有某个文件的写入权限

[root@localhost chapter4]# [ -e file1 -a -w file1 ]
[root@localhost chapter4]# echo $?
0

条件判断语句

条件判断语句是一种最简单的流程控制语句。该语句使得程序根据不同的条件来执行不同的程序分支。本节将介绍Shell程序设计中的简单的条件判断语句。

使用简单的if语句进行条件判断

条件判断语句使用if语句来实现。最简单的if语句的语法如下:

if expression
then
		statement1
		statement2
		...
fi

在上面的语法中,expression通常代表一个条件表达式,但是也可以是Shell命令。
为了使得代码更加紧凑,在某些情况下,我们可以将if子句和then子句写在同一行中。此时,需要在expression表达式后面加上一个分号,如下:

if expression; then
		statement1
		statement2
fi

分号的作用是表示if子句已经结束,后面的代码是then子句。
【例4-18】通过条件测试判断文件类型

#!/bin/bash
#使用条件测试判断/bin/bash是否是一个常规文件
if [ -f /bin/bash ]
   then echo "/bin/bash is a file"
fi

运行以上程序

[root@localhost ~]# ./test.sh
/bin/bash is a file

【例4-19】通过条件测试判断文件是否创建成功

#!/bin/bash
#通过echo命令和重定向创建一个文件
echo "hello world!" > ./msg.log
if [ -f ./msg.log ]; then echo "file has been created."; fi

运行以上结果得:

[root@localhost ~]# ./test.sh
file has been created.

【例4-20】使用空命令作为判断条件

#!/bin/bash
#使用空命令作为条件
if :; then echo "always true"; fi

以上运行结果:

[root@localhost ~]# ./test.sh
always true

【例4-21】使用&&操作符代替if语句

#!/bin/bash
#使用&&操作符代替if语句
test "$(whoami)" != "root" && (echo you are using a non-privileged account; exit 1)

如果以root用户的身份执行【例4-21】,则没任何输出,如下:

[root@localhost chapter4]# ./test.sh

而当我们切换到其他用户再执行该程序时,则会输出有关提示信息,如下:

[root@localhost ~]# su - redhat
[redhat@localhost ~]$ ./test.sh
you are using a non-privileged account

if else语句的基本语法如下:

if expression
then
	statement1
	statement2
	…
else
	statement3
	statement4
	…
fi

在上面的语法中,expression表示if语句的执行条件,可以是条件表达式或者一个Shell命令。如果expression的值为真,则执行then子句中的语句statement1、statement2…。如果expression的值为假,则执行else子句中的语句,包括statement3、statement4、…,最后通过fi关键字结束整个if代码块。
【例4-22】使用if else语句进行流程控制

#!/bin/bash
#输出提示信息
echo "Please enter a number:"
#从键盘读取用户输入的数字
read num
#如果用户输入的数字大于10
if [ "$num" -gt 10 ]; then
		#输出大于10的提示信息
 	echo "The number is greater than 10."
#否则
else
	#输出小于或者等于10的提示信息
		echo "The number is equal to or less than 10."
fi

运行以上程序:

[root@localhost ~]# ./test.sh
Please enter a nukber
9
The number is equal to or less than 10
[root@localhost ~]# ./test.sh
Please enter a nukber
11
The number is greater than 10

【例4-23】演示如何通过if else语句来根据学生的百分制成绩来输出五分制成绩

#!/bin/bash

#输出提示信息
echo "Please enter a score:"
#读取用户输入数据
read score
#如果用户没有输入数据,则提示用户重新输入
if [ -z "$score" ]; then
   echo "You enter nothing.Please enter a score:"
   read score
else
   #如果用户输入的数据不对,则重新输入
   if [ "$score" -lt 0 -o "$score" -gt 100 ]; then
      echo "The score should be between 0 and 100.Please enter again:"
      read score
   else
   		#输出级别A	
  		if [ "$score" -ge 90 ]; then
     		 echo "The grade is A."
  		else
      		#输出级别B
      		if [ "$score" -ge 80 ]; then
         		echo "The grade is B."
    		else
         		#输出级别C      
         		if [ "$score" -ge 70 ]; then
            		echo "The grade is C."
         		else
            		#输出级别D
            		if [ "$score" -ge 60 ]; then
               			echo "The grade is D."
            		else
               		#输出级别E
               			echo "The grade is E."
            		fi
         		fi
      		fi
  	 	fi
	fi
fi

使用if elif语句进行多条件判断

if elif语句的基本语法如下:

if expression1
then
   statement1
   statement2
   …
elif expression2
then
   statement3
   statement4
   …
elif expression3
then
   statement5
   statement6
   …
else
   statementn
   ..
fi

在上面的语法中,expression1表示整个if elfi语句结构中的第1个条件表达式,如果该条件表达式的值为真,则执行第1个then子句中的语句statement1以及statement2等等;否则,继续下面的判断。如果表达式expression2的值为真,则执行第2个then子句中的语句,以此类推。如果所有的条件表达式的值都为假,则执行最后的else子句中的语句。最后是if elif结构的结束标志fi。
【例4-24】本例对【例4-23】进行改进,使得该程序的可读性更强

#!/bin/bash
echo "Please enter a score:"
read score
if [ -z "$score" ]; then
   echo "You enter nothing.Please enter a score:"
   read score
else
   if [ "$score" -lt 0 -o "$score" -gt 100 ]; then
      echo "The score should be between 0 and 100.Please enter again:"
      read score
   else
      #如果成绩大于90
      if [ "$score" -ge 90 ]; then
         echo "The grade is A."
      #如果成绩大于80且小于90 
      elif [ "$score" -ge 80 ]; then
         echo "The grade is B."
      #如果成绩大于70且小于80
      elif [ "$score" -ge 70 ]; then
         echo "The grade is C."
      #如果成绩大于60且小于70
      elif [ "$score" -ge 60 ]; then
         echo "The grade is D."
      #如果成绩小于60
      else
         echo "The grade is E."
      fi
   fi
fi

使用exit语句退出程序

exit语句的基本作用是终止Shell程序的执行。除此之外,exit语句还可以带一个可选的参数,用来指定程序退出时的状态码。exit语句的基本语法如下:
exit status
其中,status参数表示退出状态,该参数是一个整数值,其取值范围为0~255。与其他的Shell命令的一样,Shell程序的退出状态也储存在系统变量$?中,因此,用户可以通过该变量取得Shell程序返回给父进程的退出状态码。
【例4-25】演示在不同的情况下,程序返回不同的状态码

#!/bin/bash
#使用echo语句输出字符串
echo hello world!
#使用$?变量获取echo语句的执行状态
echo $?
#执行一个无效的命令
aaa
#输出执行状态
echo $?
#退出
exit 120

运行以上程序:

[root@localhost ~]# ./test.sh
hello world!
0
./test.sh: line 4: aaa: command not found
127
[root@localhost ~]# echo $?
120

【例4-26】使用if和exit语句,使得程序在适当的时候退出

#!/bin/bash
#如果文件已经存在,则直接退出
if [ -e "$1" ]
then
   echo "file $1 exists."
   exit 1
#如果文件不存在,则创建文件
else
   touch "$1"
   echo "file $1 has been created."
   exit 0
fi

运行以上程序

[root@localhost ~]# ./test.sh file1
file file1 exists.
[root@localhost ~]# ll file*
-rw-r--r--. 1 root root   0 Jun 12 04:36 file1
[root@localhost ~]# ./test.sh file3
file file3 has been created
[root@localhost ~]# ll file*
-rw-r--r--. 1 root root   0 Jun 12 04:36 file1
-rw-r--r--. 1 root root   0 Jun 12 05:33 file3

多条件判断语句case

case语句的基本语法如下:

case variable in
value1)
   statement1
   statement2
   ...
   statementn;;
value2)
   statement1
   statement2
   ...
   statementn;;
value3)
   statement1
   statement2
   ...
   statementn;;
...
valuen)
   statement1
   statement2
   ...
   statementn;;
*)
   statement1
   statement2
   ...
   statementn;;
esac

在上面的语法中,variable是一个变量,case语句会将该变量的值与每value1~valuen中的每个值相比较,如果与某个value的值相等,则执行该value所对应的一组语句。当遇到“;;”符号时,就跳出case语句,执行esac语句后面的语句。如果没有任何一个值与variable的值相匹配,则执行*后面的一组语句。

利用case语句处理选项参数

使用case语句来处理选项参数在Shell中非常普遍,尤其是/etc/init.d目录中服务脚本,几乎都含有一个或者多个case语句。

利用case语句处理用户输入

【例4-27】说明case语句的使用方法

#!/bin/bash
#输出提示信息
echo "Hit a key,then hit return."
#读取用户按下的键
read keypress
#case语句开始
case "$keypress" in
   #小写字母
   [[:lower:]])
      echo "Lowercase letter.";;
   #大写字母
   [[:upper:]])
      echo "Uppercase letter.";;
   #单个数字
   [0-9])
      echo "Digit.";;
   #其他字符
   *)
      echo "other letter.";;
esac

运行以上程序

[root@localhost ~]# ./test.sh
Hit a key,then hit return.
656
other letter.
[root@localhost ~]# ./test.sh
Hit a key,then hit return.
2
Digit.
[root@localhost ~]# ./test.sh
Hit a key,then hit return.
a
Lowercase letter.
[root@localhost ~]# ./test.sh
Hit a key,then hit return.
W
Uppercase letter.

case语句总结:
case语句结构特点如下:
case行尾必须为单词 in ,每个模式必须以右括号 ) 结束
双分号 ;; 表示命令序列结束
case语句结构特点如下:
匹配模式中可以使用方括号表示一个连续的范围,如[0-9];使用竖杠符号“|”表示或。
最后的“*)”表示默认模式,当使用前面的各种模式均无法匹配该变量时,将执行“*)”后的命令序列。
case实例:
由用户从键盘输入一个字符,并判断该字符是否为字母、数字或者其他字符, 并输出相应的提示信息。

#!/bin/bash
read -p "press some key ,then press return :" KEY
case $KEY in //read -p表示提示语句
[a-z]|[A-Z])
echo "It's a letter."
;;
[0-9]) 
echo "It's a digit."
;;
*)
echo "It's function keys,Spacebar or other keys."
;;
esac

运行以上程序

[root@localhost ~]# ./test.sh
press some key,then press return :e
It's a letter.
[root@localhost ~]# ./test.sh
press some key,then press return :G
It's a letter.
[root@localhost ~]# ./test.sh
press some key,then press return :5
It's a digit.
[root@localhost ~]# ./test.sh
press some key,then press return :dexn6
It's function keys,Spacebar or other keys.

case实例:

#!/bin/sh 
case $1 in
        start | begin) 
          echo "start something"
        ;; 
        stop | end) 
          echo "stop something"
        ;; 
        *) 
          echo "Ignorant"
        ;; 
esac

运行以上程序

[root@localhost ~]# ./test.sh stop
stop something
[root@localhost ~]# ./test.sh begin
start something
[root@localhost ~]# ./test.sh test
Ignorant

判断系统
有时候,您所写的Script可能会跨越好几种平台,如Linux、FreeBSD、Solaris等等,而各平台之间,多多少少都有不同之处,有时候需要判断目前正在那一种平台上执行。此时,我们可以利用uname来找出系统信息。

#!/bin/sh 
 SYSTEM=`uname -s` 
 case $SYSTEM in 
     Linux) 
         echo "My system is Linux" 
         echo "Do Linux stuff here..." 
     ;; 
     FreeBSD) 
         echo "My system is FreeBSD" 
         echo "Do FreeBSD stuff here..." 
     ;; 
     *) 
         echo "Unknown system : $SYSTEM" 
         echo "I don't what to do..." 
     ;; 
 esac

运行以上程序

[root@localhost ~]# ./test.sh
My system is Linux
Do Linux stuff here...

运算符

本节将介绍算术运算符、位运算符以及自增/自减运算符等的使用方法。

算术运算符

与其他的程序设计语言一样,Shell中的算术运算符也主要包括加(+)、减(-)、乘(*)、除(/)、求余(%)以及幂运算(**)等。表4-4列出了常用的算术运算符以及使用方法。
Shell中的条件测试和判断语句_第3张图片
在Linux Shell中,用户可以通过4种方式来执行算术运算,这4种方式分别如下。
1.使用expr外部程序
expr是一个Shell命令,可以计算某个表达式的值,其基本语法如下:
expr expression
其中,express是要计算的表达式。
【例4-28】演示使用expr命令来计算不同的算术运算

#!/bin/bash
#计算2和100的差,即-98
result=`expr 2 - 100`
echo "$result"
#计算2和100的和,即102
result=`expr 2 + 100`
echo "$result"
#计算2和5的乘积,即10
result=`expr 2 \* 5`
echo "$result"
#计算24和8的商,即3
result=`expr 24 / 8`
echo "$result"
#先计算2和6的差,然后再乘以12,即-48
result=`expr \( 2 - 6 \) \* 12`
echo "$result"
#错误的语法
result=`expr 2+5`
echo "$result"
#错误的语法
result=`expr 2-4*9`
echo "$result"
#错误的语法
result=`expr 1-(4-7)`
echo "$result"

运行以上程序

[root@localhost ~]# ./test.sh
-98
102
10
3
-48
2+5
2-4*9
./test.sh: command substitution: line 16: syntax error near unexpected token `('
./test.sh: command substitution: line 16: `expr 1-(4-7)'

expr命令扩展
expr在linux中是一个功能非常强大的命令。通过学习做一个小小的总结。
1、计算字符串的长度。我们可以用awk中的length(s)进行计算。我们也可以用echo中的echo ${#string}进行计算,当然也可以expr中的expr length $string 求出字符串的长度。
举例

[root@localhost ~]# string="hello,everyone my name is xiaoming"
[root@localhost ~]# echo ${#string}
34
[root@localhost ~]# expr length "$string"
34

2、expr中的expr index $string substring索引命令功能在字符串$string上找出substring中字符第一次出现的位置,若找不到则expr index返回0或1。
举例:

[root@localhost ~]# string="hello,everyone my name is xiaoming"
[root@localhost ~]# expr index "$string" m
16
[root@localhost ~]# expr index "$string" nihao
1

3、expr中的expr match $string substring命令在string字符串中匹配substring字符串,然后返回匹配到的substring字符串的长度,若找不到则返回0。
举例

[root@localhost ~]# string="hello,everyone my name is xiaoming"
[root@localhost ~]# expr match "$string" my		//有问题
0
[root@localhost ~]# expr match "$string" hell.*
34
[root@localhost ~]# expr match "$string" hell
4
[root@localhost ~]# expr match "$string" small
0

4、在shell中可以用{string:position}和{string:position:length}进行对string字符串中字符的抽取。第一种是从position位置开始抽取直到字符串结束,第二种是从position位置开始抽取长度为length的子串。而用expr中的expr substr $string $position $length同样能实现上述功能。
举例:

[root@localhost ~]# string="hello,everyone my name is xiaoming"
[root@localhost ~]# echo ${string:10}
yone my name is xiaoming
[root@localhost ~]# echo ${string:10:5}
yone
[root@localhost ~]# echo ${string:10:10}
yone my na
[root@localhost ~]# expr substr "$string" 10 5
ryone

注意:echo ${string:10:5}和 expr substr “$string” 10 5的区别在于${string:10:5}以0开始标号而expr substr “$string” 10 5以1开始标号。
5、删除字符串和抽取字符串相似KaTeX parse error: Expected '}', got '#' at position 8: {string#̲substring}为删除st…{string##substring}为删除string开头处与substring匹配的最长字符子串。
举例

[root@localhost ~]# string="20091111 readnow please"
[root@localhost ~]# echo ${string#2*1}
111 readnow please
[root@localhost ~]# echo ${string##2*1}
readnow please

解析:第一个为删除2和1之间最短匹配,第二个为删除2和1之间的最长匹配。

6、替换子串${string/substring/replacement}表示仅替换一次substring相配字符,而${string//substring//replacement}表示为替换所有的substring相配的子串。
举例:

[root@localhost ~]# string="you and you with me"
[root@localhost ~]# echo ${string/you/me}
me and you with me
[root@localhost ~]# echo ${string//you/me}
me and me with me

2.使用$((… ))
使用这种形式来进行算术运算写法比较自由,毋需对运算符和括号做转义处理,可以采用松散或者紧凑的格式来书写表达式。
【例4-29】演示如何使用$((…))符号进行算术运算

#!/bin/bash
#紧凑格式,计算3和6的和
result=$((3+6))
echo "$result"
#松散格式,计算3和9的和
result=$(( 3 + 9 ))
echo "$result"
#计算3和6的乘积
reuslt=$(( 3 * 6 ))
echo "$result"
#计算7和5的商
result=$(( 7 / 5 ))
echo "$result"
#计算8和3的余数
result=$(( 8 % 3 ))
echo "$result"
#复合运算
result=$(( ( 1 - 4 ) * 5 ))
echo "$result"

运行以上程序

[root@localhost ~]# ./test.sh
9
12
18
1
2
-15

3.使用$[…]
【例4-30】演示如何使用方括号来进行算术运算

#!/bin/bash
#加法运算
result=$[4+5]
echo "$result"
#复合运算
result=$[(1+2)*3]
echo "$result"
#幂运算
result=$[2**4]
echo "$result"

运行以上程序

[root@localhost ~]# ./test.sh
9
9
16

shell中$(),$(()),${},``的区别
命令替换
在bash中,$( )与` `(反引号)都是用来作命令替换的。
命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
exp 1

[root@localhost ~]# echo today is $(date "+%Y-%m-%d")
today is 2019-06-16
[root@localhost ~]# echo today is `date "+%Y-%m-%d"`
today is 2019-06-16

$( )与``
在操作上,这两者都是达到相应的效果,但是建议使用$( ),理由如下:
``很容易与’'搞混乱,尤其对初学者来说,而$( )比较直观。
最后,$( )的弊端是,并不是所有的类unix系统都支持这种方式,但反引号是肯定支持的。

exp 2

[root@localhost ~]# echo Linux `echo Shell` echo today is `date "+%Y-%m-%d"```
Linux Shell echo today is 2019-06-16   #过多使用``会有问题
[root@localhost ~]# echo Linux `echo Shell $(echo today is $(date "+%Y-%m-%d"))`
Linux Shell today is 2019-06-16    ``和$()混合使用
[root@localhost ~]# echo Linux $(echo Shell $(echo today is $(date "+%Y-%m-%d")))
Linux Shell today is 2019-06-16    #多个$()同时使用也不会有问题

${ }变量替换
一般情况下,$var与${var}是没有区别的,但是用${ }会比较精确的界定变量名称的范围
exp 1

[root@localhost ~]# A=Linux
[root@localhost ~]# echo $AB    #表示变量AB

[root@localhost ~]# echo ${A}B    #表示变量A后连接着B
LinuxB
${}可以取路径、文件名、后缀
先赋值一个变量为一个路径,如下:
file=/dir1/dir2/dir3/my.file.txt

命令               解释                                          结果
${file#*/}    拿掉第一条 / 及其左边的字符串    dir1/dir2/dir3/my.file.txt
[root@localhost ~]# echo ${file#*/}
dir1/dir2/dir3/my.file.txt

${file##*/}    拿掉最后一条 / 及其左边的字符串    my.file.txt
[root@localhost ~]# echo ${file##*/}
my.file.txt

${file#*.}    拿掉第一个 . 及其左边的字符串    file.txt

[root@localhost ~]# echo ${file#*.}
file.txt

${file##*.}    拿掉最后一个 . 及其左边的字符串    txt
[root@localhost ~]# echo ${file##*.}
txt

${file%/*}    拿掉最后一条 / 及其右边的字符串    /dir1/dir2/dir3
[root@localhost ~]# echo ${file%/*}
/dir1/dir2/dir3

${file%%/*}    拿掉第一条 / 及其右边的字符串    (空值)
[root@localhost ~]# echo ${file%%/*}
(空值)

${file%.*}    拿掉最后一个 . 及其右边的字符串    /dir1/dir2/dir3/my.file
[root@localhost ~]# echo ${file%.*}
/dir1/dir2/dir3/my.file

${file%%.*}    拿掉第一个 . 及其右边的字符串    /dir1/dir2/dir3/my
[root@localhost ~]# echo ${file%%.*}
/dir1/dir2/dir3/my
[root@localhost ~]# file=/dir1/dir2/dir3/my.file.txt
[root@localhost ~]# echo ${file#*/}
dir1/dir2/dir3/my.file.txt
[root@localhost ~]# echo ${file##*/}
my.file.txt
[root@localhost ~]# echo ${file#*.}
file.txt
[root@localhost ~]# echo ${file##*.}
txt
[root@localhost ~]# echo ${file%/*}
/dir1/dir2/dir3
[root@localhost ~]# echo ${file%%/*}

[root@localhost ~]# echo ${file%.*}
/dir1/dir2/dir3/my.file
[root@localhost ~]# echo ${file%%.*}
/dir1/dir2/dir3/my

记忆方法如下:
# 是去掉左边(在键盘上 # 在 $ 之左边)
% 是去掉右边(在键盘上 % 在 $ 之右边)
单一符号是最小匹配;两个符号是最大匹配
*是用来匹配不要的字符,也就是想要去掉的那部分
还有指定字符分隔号,与*配合,决定取哪部分


${}取子串及替换
命令 解释    结果
${file:0:5}    提取最左边的 5 个字节             /dir1
${file:5:5}    提取第 5 个字节右边的连续 5 个字节      /dir2
${file/dir/path} 将第一个 dir 提换为 path           /path1/dir2/dir3/my.file.txt
${file//dir/path}     将全部 dir 提换为 path            /path1/path2/path3/my.file.txt
${#file}           获取变量长度                  27

[root@localhost ~]# file=/dir1/dir2/dir3/my.file.txt
[root@localhost ~]# echo ${file:0:5}
/dir1
[root@localhost ~]# echo ${file:5:5}
/dir2
[root@localhost ~]# echo ${file/dir/path}
/path1/dir2/dir3/my.file.txt
[root@localhost ~]# echo ${file//dir/path}
/path1/path2/path3/my.file.txt
[root@localhost ~]# echo ${#file}
27

根据状态为变量赋值
${file-my.file.txt}
若 $file 没设定,则使用 my.file.txt 作传回值,空值及非空值不作处理
[root@localhost ~]# echo ${test-my.file.txt} //test变量不存在
my.file.txt

${file:-my.file.txt}
若 $file 没有设定或为空值,则使用 my.file.txt 作传回值,非空值时不作处理
${file+my.file.txt}
若$file 设为空值或非空值,均使用my.file.txt作传回值,没设定时不作处理
${file:+my.file.txt}
若 $file 为非空值,则使用 my.file.txt 作传回值,没设定及空值不作处理
${file=txt}
若 $file 没设定,则回传 txt ,并将 $file 赋值为 txt,空值及非空值不作处理
${file:=txt}
若 $file 没设定或空值,则回传 txt ,将 $file 赋值为txt,非空值时不作处理
${file?my.file.txt}
若 $file 没设定,则将 my.file.txt 输出至 STDERR,空值及非空值不作处理
${file:?my.file.txt}
若 $file没设定或空值,则将my.file.txt输出至STDERR,非空值时不作处理
tips:
以上的理解在于, 你一定要分清楚 unsetnullnon-null 这三种赋值状态. 一般而言, : 与 null 有关, 若不带 : 的话, null 不受影响, 若带 : 则连 null 也受影响.
${}在数组中的用法
A=“a b c def” # 定义字符串
A=(a b c def) # 定义字符数组
${A[@]}:返回数组全部元素,结果为:a b c def
${A[*]}:同上,结果为a b c def
${A[0]}:返回数组第一个元素,结果为a
${#A[@]}:返回数组元素总个数,结果为4
${#A[*]}:同上,结果为4
${#A[3]}:返回第四个元素的长度,即def的长度,结果为3
A[3]=xzy:将第四个组数重新定义为 xyz

[root@localhost ~]# echo ${A[@]}
a b c def
[root@localhost ~]# echo ${A[*]}
a b c def
[root@localhost ~]# echo ${A[0]}
a
[root@localhost ~]# echo ${#A[@]}
4
[root@localhost ~]# echo ${#A[*]}
4
[root@localhost ~]# echo ${#A[3]}
3
[root@localhost ~]# A[3]=xyz
[root@localhost ~]# echo ${A[@]}
a b c xyz

(())重定义变量值

[root@localhost ~]# a=5;b=7
[root@localhost ~]# ((a++))
[root@localhost ~]# echo $a
6
[root@localhost ~]# ((a--));echo $a
5
[root@localhost ~]# ((ab));echo $?
1

4.使用let命令
使用let命令可以执行一个或者多个算术表达式,其中的变量名毋需使用$符号。如果表达式中含有空格或者其他特殊字符,则必须将其引用起来。
【例4-31】演示使用let命令来执行算术运算

#!/bin/bash

#定义变量
n=10
#加法运算
let n=n+1
echo "$n"
#乘法运算
let n=n*10
echo "$n"
#幂运算
let n=n**2
echo "$n"

对于let的理解:

[root@foundation0 ~]# cat test.sh 
#!/bin/bash
t=122
let t=$t+1
echo $t
[root@foundation0 ~]# ./test.sh 
123
[root@foundation0 ~]# cat test1.sh 
#!/bin/bash
t=122
t=$t+1
echo $t
[root@foundation0 ~]# ./test1.sh 
122+1
在SHELL中,变量是没有类型的,如果变量的值都是数字,那么其可以视为整数,如果有字母,那么就当做字符串。

复合算术运算符
Shell中的条件测试和判断语句_第4张图片

位运算符

位运算通常出现在整数间,它针对的不是整个整数,而是其二进制表示形式中的某个或者某些位(bit)。例如,2>>1是将二进制形式的2,即10,左移1位,从而变成100,即4。下表列出了常用的位运算符。
Shell中的条件测试和判断语句_第5张图片
Shell中的条件测试和判断语句_第6张图片
【例4-32】演示位运算符的使用方法

#!/bin/bash
#左移运算
result=$[ 2 << 3 ]
echo "$result"
#右移运算
result=$[ 8 >> 2 ]
echo "$result"
#按位与运算
result=$[ 8 & 4 ]
echo "$result"
#按位非运算
result=$[ ~8 ]
echo "$result"
#按位异或运算
result=$[ 10 ^ 6 ]
echo "$result"

运行以上程序

[root@localhost ~]# ./test.sh
16
2
0
-9
12
复合位运算符

Shell中的条件测试和判断语句_第7张图片
或与异或:
按位或运算: 按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位(也就是最后一位)相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。 例如:9|5可写算式如下: 00001001|00000101 00001101 (十进制为13)可见9|5=13
按位异或运算: 如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
异或也叫半加运算,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。
若x是二进制数0101,y是二进制数1011;
则x⊕y=1110
只有在两个比较的位不同时其结果是1,否则结果为0
即“两个输入相同时为0,不同则为1”!
【例4-33】演示表4-7中列出的复合位运算符的使用方法

#!/bin/bash

#定义变量x
x=5
#执行左移赋值复合运算
let "x<<=4"
echo "$x"
#执行右移赋值复合运算
let "x>>=2"
echo "$x"
#执行按位或赋值运算
let "x|=2"
echo "$x"

运行以上程序

[root@localhost ~]# ./test.sh
80
20
22

自增/自减运算符

在Shell中,还有一类称为自增或者自减的运算符,这类运算符的作用是将某个变量自动加1或者减1。这类运算符一共有4种,分别是前置自增、前置自减、后置自增和后置自减。
Shell中的条件测试和判断语句_第8张图片
【例4-34】演示自增或者自减运算符的使用方法

#!/bin/bash
#定义变量x
x=5
#将变量x先自增,然后再计算表达式的值
x=$[ x + (++x) ]
echo "$x"
#将变量先自减,然后再计算表达式的值
x=$[ --x ]
echo "$x"
#先计算表达式的值,然后再自增
x=$((x++))
echo "$x"
#先计算表达式的值,然后再自减
x=$(( x-- ))
echo "$x"

运行以上程序

[root@localhost ~]# ./test.sh
11
10
10
10

数字常量的进制

在Shell中,用户可以使用2种语法来表示不同的进制,首先是增加前缀,例如以0开头的数字表示八进制,以0x开头的数字表示十六进制。第2种语法是使用井号“#”,例如2#1000表示二进制,8#42表示八进制。
【例4-35】演示不同的进制的表示方法

#!/bin/bash
#十进制20
((x=20))
echo "$x"
#八进制20
((x=020))
echo "$x"
#十六进制20
((x=0x20))
echo "$x"

运行以上程序

[root@localhost ~]# ./test.sh
20
16
32

【例4-36】演示使用井号“#”来表示不同进制的方法

#!/bin/bash
#二进制
((x="2#100000"))
echo "$x"
#八进制
((x=8#123))
echo "$x"
#十六进制
((x=16#32))
echo "$x"

运行以上程序

[root@localhost ~]# ./test.sh
32
83
50

你可能感兴趣的:(linux,shell,linux)