bash shell命令学习之结构化命令篇

本博客内容来自《Linux命令行与shell脚本编程大全》第十二、十三章

目录

1、使用 if-then 语句

2、if-then-else语句

3、嵌套if

4、test命令

数值比较

字符串比较

字符串相等性

字符串顺序

字符串大小

文件比较

5、复合条件测试

6、高级特性

使用双括号

使用双方括号

7、case命令

8、for命令

读取列表中的值

读取列表中复杂的值

从变量读取列表

从命令中读取值

更改字段分隔符

用通配符读取目录

9、使用C语言风格的for命令

10、while命令


1、使用 if-then 语句

if-then语句格式如下:

if command

then

  commands   ##多个命令行可以依次执行

fi

或者有些人喜欢这么写:

if command; then

  commands

fi

该命令会运行if后面的命令,如果该命令的退出状态码是0(成功运行),位于then部分的命令就会被执行,否则不执行。下面是一个简单的例子:

[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test1.sh 
/root/12
it workded!
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test1.sh 
#!/bin/bash
# testing the if-then
if pwd
then
  echo it workded!
fi

2、if-then-else语句

格式为:

if command

then

    commands

else

   commands

fi

这个就与我们比较熟悉的if-else语法有点相似了~

3、嵌套if

嵌套语句在判断多个逻辑时非常有效:

if command

then

   commands

else

    ...

    if command

    then

        commands

    fi

fi

上述表达式虽然满足要求,但是不易阅读,可以用以下形式:

if command1

then

    commands

elif command2  ##很像我们JAVA里面的 else if 形式

then

    commands

fi

那么,也就不难可以知道还有如下形式:

if command1

then

    commands

elif command2

then

    commands

else

    commands

fi

4、test命令

由于if-then语句只能测试命令退出状态码这一条件,无法对其他条件进行判定,所以功能有限。

test命令提供了在if-then语句中测试不同条件的途径。test命令的格式为:

test condition

与if-then语句结合起来,形式为:

if test condition

then

    command

fi

test后面的condition部分一定要写,否则会返回非零的退出状态码

常见的test后面跟的condition举例如下:

test $variable   #测试变量是否为空,非空时if test返回0

而另一种条件测试方法无需声明test命令:

if  [ condition ]   ##condition前后必须加上一个空格,否则报错

then

    commands

fi

test命令可以判断三类条件

数值比较

字符串比较

文件比较

数值比较

最常用的情形,对两个数值进行比较,但是要注意,必须得是整数

n1 -eq n2    ##检查是否相等

n1 -ge n2    ##大于等于

n1 -gt n2    ##大于

n1 -le n2    ##小于等于

n1 -lt n2    ##小于

n1 -ne n2    ##不相等

举例如下:

[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test2.sh 
the test value 10 is greater than 5
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test2.sh 
#!/bin/bash
value1=10
if [ $value1 -gt 5 ]
then
  echo the test value $value1 is greater than 5
fi

字符串比较

比较字符串比较繁琐

  • 字符串相等性

格式

str1 = str2  ##检查str1是否和str2相同

str1 != str2

  • 字符串顺序

需要注意的地方:

1.大于号和小于号必须转义,否则shell会把他们当做重定向符号,把字符串值当做文件名

2.大于和小于顺序和sort命令所采用的不同

由于问题一,因此在比较字符串时需要使用:

[ $val1 \> $val2 ]

对于问题二,仅在比较大小写字母时会遇到,在比较测试中,大写字母被认为小于小写字母,但sort命令相反。

  • 字符串大小

-n和-z参数可以检查一个变量是否含有数据

if [ -n $val ] ##判断变量val是否为非null(空)可以把-n中的-理解为取反的意思

if [ -z $val ]  ##判断变量val是否长度为0

  • 文件比较

这类比较测试可能是shell中最为强大且用的最多的形式,允许用户测试Linux文件系统上文件和目录的状态。

-d file      ##检查file是否存在并是一个目录 directory

-e file      ##检查file是否存在

-f file      ##检查file是否存在并是一个文件

-r file      ##检查file是否存在且可读

-s file     ##检查file是否存在且非空

-w file     ##检查file是否存在并可写

-x file     ##检查file是否存在且可执行

-O file    ##检查file是否存在并属于当前用户所有

-G file    ##检查file是否存在并且默认组与当前用户相同,注意这个默认组

file1 -nt file2    ##检查file1是否比file2新,通过检查文件日期实现

file1 -ot file2    ##检查file1是否比file2旧

例子如下:

[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test3.sh 
#!/bin/bash
##-d 检查目录
if [ -d /root/12 ]
then
  echo "the directory /root/12 exists"
else
  echo "the directory /root/12 dose not exist"
fi
##-e 检查目录
if [ -e /root/12 ]
then
  echo "the directory /root/12 exists"
else
  echo "the directory /root/12 dose not exist"
fi
##-e 检查文件
if [ -e /root/12/test4.sh ]
then
  echo "the file /root/12/test4.sh exists"
else
  echo "the file /root/12/test4.sh dose not exist"
fi

##创建文件
touch /root/12/test4.sh
##-e 检查文件
if [ -e /root/12/test4.sh ]
then
  echo "the file /root/12/test4.sh exists"
else
  echo "the file /root/12/test4.sh dose not exist"
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test3.sh 
the directory /root/12 exists
the directory /root/12 exists
the file /root/12/test4.sh dose not exist
the file /root/12/test4.sh exists

-e参数可以用于文件和目录,但要确定指定对象为文件的话必须用-f参数

5、复合条件测试

if-then语句允许你使用布尔逻辑来组合测试,有两种布尔运算符可用:

[ condition1 ] && [ condition2 ]

[ condition1 ] || [ condition2 ]

跟其他编程语言性质一致,不再赘述。

6、高级特性

使用双括号

双括号命令可以在比较过程中使用高级数学表达式。命令格式如下:

(( expression ))

双括号命令中会用到的其他运算符,与C语言中的基本一致:

val++

val--

++val

--val

!

~

**   ##幂运算

<< 左位移

>> 右位移

&

|

&&

||

例如:

[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test4.sh 
#!/bin/bash
val1=10
#
if (( $val1 ** 2 > 90 ))
then
  ((  val2 = $val1 ** 2 ))
  echo the square of $val1 is $val2.
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test4.sh 
the square of 10 is 100.

使用双方括号

双方括号命令提供了针对字符串比较的高级特性,命令格式如下:

[[ expression ]]

双方括号里面的expression使用了test命令中采用的标准字符串比较,但它提供了test命令未提供的特性——模式匹配

在模式匹配中,可以定义正则表达式来匹配字符串值,使用双等号==:

例如:

[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test5.sh 
#!/bin/bash
if [[ $USER == r*t ]]
then
  echo hello $USER
else
  echo "sorry, I don't know you."
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test5.sh 
hello root

7、case命令

与C语言中的case命令类似,shell中的case命令主要适用于一个变量存在多种可能值的情况

格式如下:

case variable in

pattern1) commands1;;

pattern2) commands2;;

pattern3 | pattern4) commands3;;

*) default commands;;

esac

例如:

[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test6.sh 
Welcome, root!
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test6.sh 
#!/bin/bash
case $USER in
ZhangSan)
  echo Welcome, ZhangSan
  echo Nice to meet you.;;
LiSi)
  echo Welcome, LiSi
  echo Nice to meet you.;;
WangWu | ZhaoLiu)
  echo Welcome, WangWu or Zhaoliu
  echo Nice to meet you.;;
*)
  echo Welcome, root!;;
esac
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test6.sh 
Welcome, root!

8、for命令

for命令的基本格式:

for var in list

do

    commands

done

在do和done之间,$var变量包含着这次迭代对应的当前列表中的值。

也可以用如下格式:

for var in list; do

    commands

done

那么list如何指定呢?

读取列表中的值

第一种是直接在in后面列出多个值,空格隔开

for city in Hangzhou Shanghai Fuzhou Xiamen Beijing

do

    the next most pupular city is $city

done

读取列表中复杂的值

for循环假定每个值都是用空格分割,如果原始值中本来就带了空格,必须在这些词上增加双引号圈起来

for city in "Hang zhou" "Shang hai" "Fu zhou" "Xia men" "Bei jing"

do

    the next most pupular city is $city

done

从变量读取列表

通常shell脚本中,我们会将多个值存储在一个变量中,然后遍历这个变量即可:

cities="Hangzhou Shanghai Fuzhou Xiamen Beijing"

cities=$cities " Chongqing"

for city in $cities

do

    the next most pupular city is $city

done

从命令中读取值

生成列表所需值的另外一个途径就是使用命令的输出,可以用命令替换来执行任何能够产生输出的命令

file=cities  ##cities是同一个目录下存储了城市名的文件

for city in $(cat $file)

do

    the next most pupular city is $city

done

其中,cat $file将会输出:

Hangzhou

Shanghai

Fuzhou

Xiamen

Beijing

可以看到for循环支持变量中按行存储的值,但是如果这些值中间有空格。。。那for还是会识别这个空格并将值一分为二,怎么办?继续往下看。

更改字段分隔符

造成以上问题的原因是特殊的环境变量IFS(internal field separator)内部字段分隔符,一般bash shell中,IFS主要包括以下三种:

空格

制表符

换行符

可以通过set查看变量IFS的值(\t前面是个空格):

IFS=$'  \t\n'

补充一下基础知识:

\r:回车符,返回到这一行的开头,return的意思。

\n:换行符,到下一行的同一位置,纵坐标相同,new line的意思。

\t:制表符,为了在不使用表格的情况下,上下对齐,table的意思。

Enter 相当于\n\r,所以Enter的标识为 往下,再往前。当然,\n\r等价于\r\n。

我们可以在shell脚本中临时更改IFS这个环境变量的值来限制被bash shell当做字段分隔符的字符,可以在脚本中加入一句:

IFS=$'\n'

这样就能使用列表中包含空格的值了。需要注意,如果脚本量比较大,只在脚本中某个环节修改IFS的话,需要及时恢复默认值:

IFS.OLD=$IFS

IFS=$'\n'

<在代码中使用新的IFS>

IFS=$IFS.OLD

IFS还有多种用途,如果你想遍历一个文件中用冒号分割的值(如/etc/passwd)要做的就是将IFS的值设为冒号:

IFS=:

如果要指定多个IFS字段,只要将他们在赋值行串起来就行:

IFS=$'\n':;"

用通配符读取目录

可以通过for命令来自动遍历目录中的文件:

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test12
#!/bin/bash

for file in /root/*
do
  if [ -d "$file" ]
  then
    echo $file is a directory.
  elif [ -f "$file" ]
  then
    echo $file is a file.
  fi
done
[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test12
/root/12 is a directory.
/root/123 is a file.
/root/file1 is a file.
/root/final is a directory.
/root/FS is a directory.

在Linux中目录和文件可能包含空格,为了适应这种情况需要将遍历的file遍历用双引号圈起来。

9、使用C语言风格的for命令

[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test11
#!/bin/bash
for (( i = 1; i <= 10; i++ ))
do
  echo the nest number is $i.
done
[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test11
the nest number is 1.
the nest number is 2.
the nest number is 3.
the nest number is 4.
the nest number is 5.
the nest number is 6.
the nest number is 7.
the nest number is 8.
the nest number is 9.
the nest number is 10.

原则就是,加双括号,语法与C语言基本一致,当然,这个表达式的存在违背了shell风格的(1)变量赋值不能有空格;(2)条件的变量要以$开头。C语言风格的代码还可以有多个变量。

10、while命令

while命令的基本格式为:

while test command

do

    other commands

done

只要test command成立,即执行other commands

while命令的关键在于test command中的退出状态码必须随着循环不断改变,否则将成为死循环。

test command最常用的方法就是用方括号来检查循环命令中用到的shell变量的值

while [ $var -gt 0]

......

11、until命令

until命令格式如下所示:

until test commands

do

    other commands

done

 

 

与while命令相反

 

 

 

 

 

 

 

 

你可能感兴趣的:(Linux之路)