在学会了基本的命令之后,我们就可以使用这些命令来进行编程了。在Linux中的编程称为shell脚本,是将命令进行结合形成的类似Windows中批处理的东西。在这个脚本中,可以有变量和结构体。每一个程序所拥有的程序执行过程,例如:顺序执行、选择执行和循环执行都可以在脚本中体现出来。下面就对shell脚本进行介绍。

首先,shell脚本编程是过程式编程语言,也就是说shell脚本强调接下来要执行的步骤,就好像是人在对shell说接下来要做什么,要明确的指出每一步的方法。然后shell还是脚本类语言,它不需要编译,可以直接执行,由解释器来进行解释,所以它也是解释型语言。所以shell脚本是过程式编程语言,采用顺序执行结构,以从左到右,从上到下顺序执行所有的语句,也就是命令。

shell脚本默认为顺序进行执行,但是当我们有需要的时候可以进行跳转,来实现选择和循环这两种执行结构。选择执行结构使用“if”或“case”命令来实现。其中“if”是根据逻辑判断的结果进行选择,“case”是根据可选的取值进行选择。先说“if”语句:

格式可以为一行就写完:

if 判断条件 ; then 命令 ; [ elif 判断条件 ; then 命令 ; ]... [ else 命令 ; ] fi

如果条件为真,则执行then后的命令,否则,不做任何操作。

if语句还可以写成多行形式,看起来更加直观(分号可省略):

if CONDITION        #CONDITION为判断条件,接下来都以英文出现
then STATEMENT       #STATEMENT为要执行的语句(命令),接下来都以英文出现
fi
if CONDITION ; then #这种格式也可以
             #但是当“then”语句和“if”在同一行的时候需要在他们直接加上分号“;”。
STATEMENT1
STATEMENT2
...
fi


上面的结构为单分支结构,意思就是只有当条件满足的时候执行,接下来说一说双分支结构,这个结构中如果条件为真,就执行then后面的命令,否则就执行else后面的命令,也就是不管条件如何,都会有一个命令来执行,而不是当条件不满足的时候跳过“if”语句。格式如下:

if CONDITION ; then
STATEMENT
...
else
STATEMENT
...
fi


比双分支结构更详细的是多分支结构,这个结构对条件的描述更加详细,能够应对多种情况。首先判断CONDITION1是否为真,如果为真,则执行第一个then后面的语句;否则就判断CONDITION2是否为真,如果为真,就执行第二个then后面的语句;否则就判断CONDITION3是否为真,如果为真,就执行第三个then后面的语句...;如果所有的CONDITION都为假,就执行else后面的语句。格式为:

if CONDITION1 ; then
STATEMENT
...
elif CONDITION2 ; then
STATEMENT
...
elif CONDITION3 ; then
  STATEMENT
  ...
...
else
STATEMENT
...
fi


接下来就以多分支为结构写一个脚本,里头为以下内容(脚本执行过程参考原先写的博客:Bash脚本):

#!/bin/bash
read -p "输入一个整数" Get#这句话是为了获取一个整数
if [ $Get -gt 5 ] ; then#这句话是在获取到一个整数之后进行判断(判断的表达式参考原先写的博客:shell脚本编程之条件测试——test)
echo "这个数大于5"
elif [ $Get -lt 5 ] ; then
echo "这个数小于5"
else echo "这个数等于5"
fi

if语句必须以fi结尾

[root@localhost blog]# bash iftest
输入一个整数3
这个数小于5
[root@localhost blog]# bash iftest
输入一个整数6
这个数大于5
[root@localhost blog]# bash iftest
输入一个整数5
这个数等于5

if后既可以跟一个test语句,也可以跟一个命令,如果是命令的话就是判断这条命令是否执行成功,成功则执行接下来的命令,否则执行“else”,比如:

写一个脚本,里头包含以下内容:

#!/bin/bash
if ls test ; then
echo "test文件存在"
else echo "test文件不存在"
fi

然后执行此脚本:

[root@localhost blog]# bash ifcom 
ls: 无法访问test: 没有那个文件或目录
test文件不存在                          #因为在当前目录下没有test这个文件或文件夹,
                                         #所以“ls test”这个命令会执行失败
                                         #所以if语句就会执行else中的内容
[root@localhost blog]# touch test
[root@localhost blog]# bash ifcom 
test
test文件存在


在这个脚本的执行过程中我们可以发现输出了很多我们并不需要的内容,所以我们可以对脚本进行如下修改来删掉这些无用的信息:

#!/bin/bash
if ls test&>/dev/null ; then  
#将if后命令的输出重定向到“/dev/null”中,这是一种常用的方法
#因为很多的时候我们不需要if后用来进行判断的命令进行输出
echo "test文件存在"
else echo "test文件不存在"
fi

if大概就是这些使用方法了,接下来说一说“case”命令。“case”命令是多分支选择结构,格式为:

case 词 in [模式 [| 模式]...) 命令 ;;]... esac

或者写成有结构的形式:

case 变量 in 
[模式 [| 模式]...) 命令 ;;]
... 
esac

模式(PATTERN)可以是:

1.普通的文本字符

2.globbing风格的通配符:

*:任意长度任意字符

?:任意的单个字符

[]:范围内的任意单个字符

[^]:范围外的任意单个字符

3.|:或

当匹配到这个模式之后就会执行这个“)”之后的命令,直到遇到两个连续的分号“;;”为止。例如:

建立一个脚本,然后在脚本中写入以下内容:

#!/bin/bash
read -p "输入a、b、c中的一个:" Get
case $Get in
a)
echo "输入的是a"
;;
b)
echo "输入的是b"
;;
c)
echo "输入的是c"
;;
esac
[root@localhost blog]# bash case 
输入a、b、c中的一个:b
输入的是b


在这个脚本中仅仅只是对相同的字符进行匹配,我们还可以使用模式进行匹配,例如:

建立一个脚本,然后在脚本中写入以下内容:

#!/bin/bash
read -p "输入一个数字或字母:" Get
case $Get in
[[:digit:]])
echo "输入的是一个数字"
;;
[[:alpha:]])
echo "输入的是一个字母"
;;
*)
echo "输入的既不是数字,也不是字母"
;;
esac
[root@localhost blog]# bash caseMode 
输入一个数字或字母:s
输入的是一个字母
[root@localhost blog]# bash caseMode 
输入一个数字或字母:1
输入的是一个数字
[root@localhost blog]# bash caseMode 
输入一个数字或字母:%
输入的既不是数字,也不是字母


在这个脚本中使用了模式进行匹配,这个模式可以和上一个例子进行组合使用。其中在最后一个选项中用到了“*”这个字符,代表了任意,也就是说当上头的任何条件都不满足的时候就执行这个选项。由此来看case要比if更加的方便使用,至少格式要比if看起来清晰。


在上面给出的所有bash脚本中都是使用read命令来进行变量数据的读入,那么下面说一说“read”这个命令:

使用格式为:

read [-a 数组] [-p 提示符] [-t 超时] [名称 ...]

名称一般为变量名或数组名。如果不写名称,则系统会将read读到的信息保存在REPLY变量中。比如:

[root@localhost blog]# read a
123
[root@localhost blog]# echo $a
123
[root@localhost blog]# read 
456
[root@localhost blog]# echo $REPLY
456

“-a”选项是输入数组

“-p”选项是为了在读入数据的时候给出提示,等同于在使用read命令之前使用echo命令输出一句不换行的文字,比如:

[root@localhost blog]# read -p "输入:"
输入:123
[root@localhost blog]# echo -n "输入:" ; read #分号“;”是同时执行多个命令(具体参考原先写的博客——多命令执行)
输入:123


“-t”选项是等待一段时间,在这段时间内如果没有输入,就跳过read命令执行接下来的命令。这个命令实现了Linux的哲学思想,就是尽量不与用户进行交互,实现自动化处理。不过在使用这个选项的时候需要注意:一旦使用-t选项定义了超时时间,我们必须在后面判断给定的变量是否为空,如果为空需要为变量提供默认值

“-s”选项是关闭回显,这个选项在输入的时候不会显示输入的内容


以上是read的一些常见的用法和选项,但是这些都是在脚本开始运行之后进行的赋值,我们还可以在脚本运行之前就进行赋值。也就是在脚本执行的时候将脚本内可能会用到的变量传进去。在脚本中存在着位置参数变量:$1, $2, $3, ...这些变量是可以在shell脚本中直接进行引用的,不同的数字分别对应着脚本执行时脚本名后头跟着的第几个参数,这些参数使用空格隔开。在编写shell脚本的时候直接使用$1...进行调用,比如:

建立一个脚本,然后在脚本中写入以下内容:

#!/bin/bash
echo "第一个参数是$1"
echo "第二个参数是$2"
echo "第三个参数是$3"
[root@localhost blog]# bash bianliang a b c
第一个参数是a
第二个参数是b
第三个参数是c

在使用位置参数的时候可以配合shift [n]命令,这个命令的功能是将位置参数左移,命令后头跟一个数字作为参数,如果没有,默认为1,在执行命令之后会将位置参数左移给出的数字那么多位,这么说可能没有看懂,那么举个例子:

在脚本中写入以下内容:

#!/bin/bash
echo \$1:$1
shift
echo \$1:$1
[root@localhost blog]# bash shift a b
$1:a
$1:b


在这个脚本中我们为第一个位置参数$1赋的值为“a”,在第一行输出的就是a,经过第二行的命令“shift”将位置参数中的内容左移默认的一位之后再输出$1,就变成了原先的第二个参数“b”

除了使用数字来引用的位置参数,还有一些使用特殊符号来引用的具有特殊功能的变量:

  $#:所有的位置参数的总数;

  $*:给出的所有位置参数的列表;当使用双引号引用时,整个参数列表被当做一个字符串;

  $@:给出的所有位置参数的列表;当时有双引号引用时,每个参数作为单独的字符串存在;

  $0:所执行的脚本文件自身的路径(当前这个被执行的脚本的名字);

比如:

更改上一个脚本,改为以下内容:

#!/bin/bash
echo "\$#:$#"
echo "\$*:$*"++
echo "\$@:$@"
echo "\$0:$0"
[root@localhost blog]# bash bianliang a b c
$#:3
$*:a b c
$@:a b c
$0:bianliang