第14章 Linux的shell编程

文档配套视频讲解链接地址

  1. 腾讯课堂视频链接地址 : 51_Shell编程_Shell变量1
  2. 腾讯课堂视频链接地址 : 52_Shell编程_read与test命令2
  3. 腾讯课堂视频链接地址 : 53_Shell编程_小节复习.3
  4. 腾讯课堂视频链接地址 : 54_Shell编程_控制语句4
  5. 腾讯课堂视频链接地址 : 55_Shell编程_小节复习5
  6. 腾讯课堂视频链接地址 : 56_Shell编程_Shell函数6

第14章 Shell编程

14.1 Shell简介

随着各式Linux系统的图形化程度的不断提高,用户在桌面环境下,通过点击、拖拽等操作就可以完成大部分的工作。

然而,许多Ubuntu Linux功能使用Shell命令来实现,要比使用图形界面交互,完成的更快、更直接

英文单词Shell可直译为“贝壳”。“贝壳”是动物作为外在保护的一种工具。

可以这样认为,Linux中的Shell就是Linux内核的一个外层保护工具,并负责完成用户与内核之间的交互

命令是用户向系统内核发出控制请求,与之交互的文本流。

Shell是一个命令行解释器,将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互。

同时,Shell为操作系统提供了内核之上的功能,直接用来管理和运行系统。

当需要重复执行若干命令,可以将这些命令集合起来,加入一定的控制语句,编辑成为Shell脚本文件,交给Shell批量执行。

1. Shell交互过程
  1. 用户在命令行提示符下键入命令文本,开始与Shell进行交互。

  2. 接着,Shell将用户的命令或按键转化成内核所能够理解的指令

  3. 控制操作系统做出响应,直到控制相关硬件设备。

  4. 然后,Shell将输出结果通过Shell提交给用户。

image-20220829102905379

2. 选择Shell

最初的UNIX Shell经过多年的发展,由不同的机构、针对不同的目的,开发出许多不同类型的Shell程序。目前流行的Shell主要有几种 :

Bourne Shell(简称sh):Bourne Shell由AT&T贝尔实验室的S.R.Bourne开发,也因开发者的姓名而得名。它是Unix的第一个Shell程序,早已成为工业标准。目前几乎所有的Linux系统都支持它。不过Bourne Shell的作业控制功能薄弱,且不支持别名与历史记录等功能。目前大多操作系统是将其作为应急Shell使用。

C Shell(简称csh):C Shell由加利福尼亚大学伯克利分校开发。最初开发的目的是改进Bourne Shell的一些缺点,并使Shell脚本的编程风格类似于C语言,因而受到广大C程序员的拥护。不过C Shell的健壮性不如Bourne Shell。

Korn Shell(简称ksh):Korn Shell由David Korn开发,解决了Bourne Shell的用户交互问题,并克服了C Shell的脚本编程怪癖的缺点。Korn Shell的缺点是需要许可证,这导致它应用范围不如Bourne Shell广泛。

Bourne Again Shell(简称bash):Bourne Again Shell由AT&T贝尔实验室开发,是Bourne Shell的增强版。随着几年的不断完善,已经成为最流行的Shell。它包括了早期的Bourne Shell和Korn Shell的原始功能,以及某些C Shell脚本语言的特性。此外,它还具有以下特点:能够提供环境变量以配置用户Shell环境,支持历史记录,内置算术功能,支持通配符表达式,将常用命令内置简化。

2. 编译型语言与解释型语言

编译型语言:需要使用编译器进行编译,之后才可以执行的语言 , 源文件是不能直接执行的

常用的编译型语言有: c , c++,java,c# ,vb , asm, go

解释型语言:不需要编译, 直接可以运行的语言, 源文件可以直接运行的语言

常用的解释性语言有: python , javascript ,PHP, sql , shell, html

Shell脚本(角色扮演的剧本, 角本,脚本)语言是解释型语言。

Shell脚本的本质:Shell命令的有序集合。

14.2 shell 编程的基本过程

  1. 第一步

建立 shell 文件, shell 文件的后缀名是.sh , 或则不写

包含任意多行操作系统命令或shell命令的文本文件

  1. 赋予shell文件执行权限 (x)

用chmod命令修改权限;

  1. 执行shell文件

直接在命令行上调用shell程序

例如:

  • 源文件
02-linuxbase/01-hello.sh
  • 源代码
#! /bin/bash

# 第一句话 表示那个可执行程序来解析shell 命令 

echo "hello world!!"

  • 运行结果
linux@ubuntu:~$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  snap  Templates  Videos  work
linux@ubuntu:~$ cd work/
linux@ubuntu:~/work$ ls
02-linuxbase
linux@ubuntu:~/work$ cd 02-linuxbase/
linux@ubuntu:~/work/02-linuxbase$ ls
linux@ubuntu:~/work/02-linuxbase$ vi 01-hello.sh
linux@ubuntu:~/work/02-linuxbase$ ls -l 01-hello.sh 
-rw-rw-r-- 1 linux linux 103 829 10:49 01-hello.sh
linux@ubuntu:~/work/02-linuxbase$ ./01-hello.sh
bash: ./01-hello.sh: 权限不够
linux@ubuntu:~/work/02-linuxbase$ chmod a+x 01-hello.sh 
linux@ubuntu:~/work/02-linuxbase$ ls -l 01-hello.sh 
-rwxrwxr-x 1 linux linux 103 829 10:49 01-hello.sh
linux@ubuntu:~/work/02-linuxbase$ ./01-hello.sh 
hello world!!
linux@ubuntu:~/work/02-linuxbase$ 

14.3 Shell变量

Shell允许用户建立变量存储数据,但不支持数据类型(整型、字符、浮点型),将任何赋给变量的值都解释为一串字符

Variable=value     # 等号的左边和右边不能有空格

命名规则同C语言中的命名规则

count=1
echo $count    # $ 访问变量中的值 
DATE=`date`    #  反引号 是取变量的输出
echo $DATE

运行结果

linux@ubuntu:~/work/02-linuxbase$ DATE=`date`
linux@ubuntu:~/work/02-linuxbase$ $DATE
2022年:未找到命令
linux@ubuntu:~/work/02-linuxbase$ echo $DATE
2022年 08月 29日 星期一 11:12:17 CST
linux@ubuntu:~/work/02-linuxbase$ 

Bourne Shell有如下四种变量

  • 用户自定义变量

  • 位置变量即 命令行参数

  • 预定义变量

  • 环境变量

1. 用户自定义变量

在shell编程中通常使用全大写变量,方便识别

$ COUNT=1

变量的调用:在变量前加$

$ echo $COUNT 

Linux Shell/bash从右向左赋值

$Y=y
$ X=$Y
$ echo $X 
y 

使用unset命令删除变量的赋值

$ Z=hello 
$ echo $Z 
hello 
$ unset Z 
$ echo $Z 
2. 位置变量
$0  与键入的命令行一样,包含脚本文件名
$1,$2,……$9  分别包含第一个到第九个命令行参数
$#   包含命令行参数的个数
$@   包含所有命令行参数:“$1,$2,……$9$?   包含前一个命令的退出状态
$*   包含所有命令行参数:“$1,$2,……$9$$   包含正在执行进程的ID号

例如:

  • 源文件
02-weizhi.sh 
  • 源代码
#! /bin/bash

echo "0=$0" 
echo "1=$1" 
echo "2=$2" 
echo "3=$3" 
echo "4=$4" 
echo "5=$5" 
echo "6=$6" 
echo "7=$7" 
echo "8=$8" 
echo "9=$9" 
echo "10=$10" 
echo "11=$11" 

echo "#=$#"
echo "@=$@"
echo "*=$*"

ls 
echo "ls -> ?=$?"   # 上一条命令执行的结果 0:成功 , 1 失败 

cd /haha
echo "cd /haha -> ?=$?"   # 上一条命令执行的结果 0:成功 , 1 失败 

echo "$ =$$"   # 程序的进程号 
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh
0=./weizhi.sh
1=
2=
3=
4=
5=
6=
7=
8=
9=
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
0=./weizhi.sh
1=s1
2=s2
3=s3
4=s4
5=s5
6=s6
7=s7
8=s8
9=s9
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
0=./weizhi.sh
1=s1
2=s2
3=s3
4=s4
5=s5
6=s6
7=s7
8=s8
9=s9
10=s10
11=s11
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
0=./weizhi.sh
1=s1
2=s2
3=s3
4=s4
5=s5
6=s6
7=s7
8=s8
9=s9
10=s10
11=s11
#=11
linux@ubuntu:~/work/02-linuxbase$ vi weizhi.sh
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
0=./weizhi.sh
1=s1
2=s2
3=s3
4=s4
5=s5
6=s6
7=s7
8=s8
9=s9
10=s10
11=s11
#=11
@=s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
linux@ubuntu:~/work/02-linuxbase$ 
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh 
0=./weizhi.sh
1=
2=
3=
4=
5=
6=
7=
8=
9=
10=0
11=1
#=0
@=
01-hello.sh  weizhi.sh
ls -> ?=0
./weizhi.sh: 第 23 行: cd: /haha: 没有那个文件或目录
cd /haha -> ?=1
linux@ubuntu:~/work/02-linuxbase$ ./weizhi.sh s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
0=./weizhi.sh
1=s1
2=s2
3=s3
4=s4
5=s5
6=s6
7=s7
8=s8
9=s9
10=s10
11=s11
#=11
@=s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
*=s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11
01-hello.sh  weizhi.sh
ls -> ?=0
./weizhi.sh: 第 24 行: cd: /haha: 没有那个文件或目录
cd /haha -> ?=1
$ =2732
linux@ubuntu:~/work/02-linuxbase$ 

3. 常用shell环境变量
HOME: /etc/passwd文件中列出的用户主目录 
IFS:Internal Field Separator, 默认为空格,tab及换行符
PATH :shell搜索路径
PS1PS2:默认提示符($)及换行提示符(>) 
TERM:终端类型,常用的有vt100,ansi,vt200,xterm等 

实例23

  • 输出环境变量的值

  • 源程序

03-huanjing.sh 
  • 源代码
#! /bin/bash

echo "HOME=$HOME"
echo "PATH=$PATH"
echo "PS1=$PS1"
echo "PS2=$PS2"
echo "TERM=$TERM"
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./03-huanjing.sh 
HOME=/home/linux
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
PS1=
PS2=
TERM=xterm-256color
linux@ubuntu:~/work/02-linuxbase$ 

14.4 shell 控制语句

1. Shell程序

shell 程序由零或多条shell语句构成。 shell语句包括三类:说明性语句、功能性语句和结构性语句。

说明性语句: 以#号开始到该行结束,不被解释执行

功能性语句: 任意的shell命令、用户程序或其它shell程序。

结构性语句:条件测试语句、多路分支语句、循环语句、循环控制语句等。

说明性语句 必不可少的: #! /bin/bash

2. 输入与输出

输出: echo

输入: read

read 命令
read 从标准输入读入一行, 并赋值给后面的变量, 等价于c语言的scanf 
其语法为:
  	read  var
把读入的数据全部赋给var
	read  var1  var2  var3
把读入行中的第一个单词(word)赋给var1, 第二个单词赋给var2, ……把其余所有的词赋给最后一个变量.
如果执行read语句时标准输入无数据, 则程序在此停留等侯, 直到数据的到来或被终止运行。

实例24

  • 源文件
04-read.sh 
  • 源代码
#! /bin/bash


echo -n "please input 1 number >:"  # -n 的意思是, 去除\n, echo 不输出\n
read var1 

echo "var1 = $var1"

echo -n "please input 3 number >:"
read var1 var2 var3 

echo "var1 = $var1"
echo "var2 = $var2"
echo "var3 = $var3"

  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./04-read.sh 
please input 1 number >:123
var1 = 123
please input 3 number >:89
var1 = 89
var2 = 
var3 = 
linux@ubuntu:~/work/02-linuxbase$ ./04-read.sh 
please input 1 number >:1
var1 = 1
please input 3 number >:123 9 7 
var1 = 123
var2 = 9
var3 = 7
linux@ubuntu:~/work/02-linuxbase$ ./04-read.sh 
please input 1 number >:123
var1 = 123
please input 3 number >:1 2 3 4 5 5 6 76 7 
var1 = 1
var2 = 2
var3 = 3 4 5 5 6 76 7
linux@ubuntu:~/work/02-linuxbase$ 

3. expr 命令

算术运算命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、乘(\*)、整除(/)和求模(%)等操作。

实例25:

  • 计算2个数的加减乘除求余
  • 源文件
05-expr.sh
  • 源代码
#! /bin/bash

echo -n "please input 2 number >:"
read num1 num2
echo "num1=$num1 , num2=$num2"

ret=`expr $num1 + $num2`
echo "$num1 + $num2 = $ret"

ret=`expr $num1 - $num2`
echo "$num1 - $num2 = $ret"

ret=`expr $num1 \* $num2`
echo "$num1 * $num2 = $ret"

ret=`expr $num1 / $num2`
echo "$num1 / $num2 = $ret"

ret=`expr $num1 % $num2`
echo "$num1 % $num2 = $ret"
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./05-expr.sh 
please input 2 number >:10 15
num1=10 , num2=15
10 + 15 = 25
10 - 15 = -5
10 * 15 = 150
10 / 15 = 0
10 % 15 = 10
linux@ubuntu:~/work/02-linuxbase$ 

4. test命令

test语句可测试三种对象:

​ 字符串 整数 文件属性

  1. 字符串测试
s1 = s2     测试两个字符串的内容是否完全一样
s1 != s2    测试两个字符串的内容是否有差异
-z s1       测试s1 字符串的长度是否为0
-n s1       测试s1 字符串的长度是否不为0
  1. 整数测试
a -eq b         测试a 与b 是否相等    # ==
a -ne b         测试a 与b 是否不相等  #  != 
a -gt b         测试a 是否大于b       # > 
a -ge b         测试a 是否大于等于b   # >=
a -lt b         测试a 是否小于b      # <
a -le b         测试a 是否小于等于b   # <=
  1. 测试文件
-e FILE    测试一个文件或目录时候存在 
-d name    测试name 是否为一个目录
-f name     测试name 是否为普通文件
-L name    测试name 是否为符号链接
-r name     测试name 文件是否存在且为可读
-w name     测试name 文件是否存在且为可写
-x name     测试name 文件是否存在且为可执行
-s name     测试name 文件是否存在且其长度不为0
f1 -nt f2   测试文件f1 是否比文件f2 更新
f1 -ot f2   测试文件f1 是否比文件f2 更旧

实例26:

  • 测试2个字符串的关系
  • 源文件
06-test-str.sh
  • 源代码
#! /bin/bash


echo -n "please input 2 string >:"
read s1 s2
echo "s1=$s1 , s2=$s2"

if test -z $s1    # 判断s1字符串的长度不为0  
then 
    echo "s1 is empty"
    exit 1
fi 

if test -z $s2    # 判断s1字符串的长度不为0  
then 
    echo "s2 is empty"
    exit 1
fi 

if test $s1 = $s2 
then 
    echo "$s1 = $s2"
else 
    echo "$s1 != $s2"
fi 

  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./06-test-str.sh 
please input 2 string >:goodbye hello
s1=goodbye , s2=hello
goodbye != hello
linux@ubuntu:~/work/02-linuxbase$ ./06-test-str.sh 
please input 2 string >:goodbye goodbye
s1=goodbye , s2=goodbye
goodbye = goodbye
linux@ubuntu:~/work/02-linuxbase$ ./06-test-str.sh
please input 2 string >:
s1= , s2=
s1 is empty

实例27:

  • 从终端输入的y/n , 读取用户输入的是y还是n
  • 源文件
07-test-yes-no.sh 
  • 源代码
#! /bin/bash


echo -n "please input [y/n] >:"
read s1 
echo "s1=$s1"

if test -z $s1    # 判断s1字符串的长度不为0  
then 
    echo "s1 is empty"
    exit 1
fi 

if test $s1 = "y" 
then 
    echo "yes"
fi 
if test $s1 = "n" 
then 
    echo "no"
fi 


  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./07-test-yes-no.sh 
please input [y/n] >:y
s1=y
yes
linux@ubuntu:~/work/02-linuxbase$ ./07-test-yes-no.sh 
please input [y/n] >:n
s1=n
no
linux@ubuntu:~/work/02-linuxbase$ ./07-test-yes-no.sh 
please input [y/n] >:
s1=
s1 is empty
linux@ubuntu:~/work/02-linuxbase$ 

实例28

  • 输入2个数, 比较2个数之间的关系(> , >= , <, <=, ==, != )

  • 源文件

08-test-numer.sh 
  • 源代码
#! /bin/bash

echo -n "please input 2 number >:"
read n1  n2 
echo "n1=$n1 , n2=$n2"


if test $n1 -gt $n2  # >  
then 
    echo "$n1 > $n2"
fi 

if test $n1 -ge $n2   # >= 
then 
    echo "$n1 >= $n2"
fi 

if test $n1 -lt $n2   # < 
then 
    echo "$n1 < $n2"
fi 

if test $n1 -le $n2   # <= 
then 
    echo "$n1 <= $n2"
fi 

if test $n1 -eq $n2   # == 
then 
    echo "$n1 == $n2"
fi 

if test $n1 -ne $n2   # != 
then 
    echo "$n1 != $n2"
fi 
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./08-test-numer.sh 
please input 2 number >:10 20
n1=10 , n2=20
10 < 20
10 <= 20
10 != 20
linux@ubuntu:~/work/02-linuxbase$ ./08-test-numer.sh 
please input 2 number >:10 10 
n1=10 , n2=10
10 >= 10
10 <= 10
10 == 10
linux@ubuntu:~/work/02-linuxbase$ ./08-test-numer.sh 
please input 2 number >:10 8
n1=10 , n2=8
10 > 8
10 >= 8
10 != 8
linux@ubuntu:~/work/02-linuxbase$

实例29

  • 测试文件的属性 , 文价是否存在 , 文件的类型(BCD-LSP), 文件的读写权限(rwx)
  • 源文件
09-test-file.sh 
  • 源代码
#! /bin/bash


echo -n "please input filename >:"
read  filename 
echo "filename=$filename"

if ! test -e $filename   # 文件不存在则报错  
then 
    echo "file not existed"
    exit 1
fi 

if test -b $filename   # 块设备文件 
then 
    echo "block"
elif test -c $filename  # 字符设备文件
then 
    echo "character"
elif test -d $filename  #目录 
then 
    echo "directory"
elif test -h $filename   # 符号链接
then 
    echo "link"
elif test -f $filename   # 普通文件
then 
    echo "regular"
elif test -S $filename   # socket文件 
then 
    echo "socket"
elif test -p $filename   # pipe文件 
then 
    echo "pipe"
fi


if test -r $filename   # 可读 
then 
    echo "read"
fi

if test -w $filename   # 可写 
then 
    echo "write"
fi

if test -x $filename   # 可执行 
then 
    echo "exec"
fi
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:/
filename=/
directory
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:/dev/sda
filename=/dev/sda
block
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:/dev/vca
filename=/dev/vca
file not existed
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:/dev/vcs
filename=/dev/vcs
character
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:09-test-file.sh
filename=09-test-file.sh
regular
linux@ubuntu:~/work/02-linuxbase$ ln -s 09 09-test-file.sh 
ln: 无法创建符号链接'09-test-file.sh': 文件已存在
linux@ubuntu:~/work/02-linuxbase$ ln -s 09-test-file.sh  09
linux@ubuntu:~/work/02-linuxbase$ ls -l 09
lrwxrwxrwx 1 linux linux 15 830 10:41 09 -> 09-test-file.sh
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:09
filename=09
regular
linux@ubuntu:~/work/02-linuxbase$ vi 09-test-file.sh 
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:09
filename=09
link
linux@ubuntu:~/work/02-linuxbase$ mkfifo myfifo
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:myfifo
filename=myfifo
pipe
linux@ubuntu:~/work/02-linuxbase$ 
linux@ubuntu:~/work/02-linuxbase$ ./09-test-file.sh 
please input filename >:09-test-file.sh
filename=09-test-file.sh
regular
read
write
exec
linux@ubuntu:~/work/02-linuxbase$ 
linux@ubuntu:~/work/02-linuxbase$ ls -l 09-test-file.sh 
-rwxrwxr-x 1 linux linux 792 830 10:46 09-test-file.sh
linux@ubuntu:~/work/02-linuxbase$ 
5. test命令的替代写法[]

在程序中可以 使用 [ ] 替代test 命令 , 这种用法就是 test 的缩写

实例30

  • 把实例29的test命令用[ ] 替代
  • 源文件
10-test-file.sh 
  • 源代码
#! /bin/bash


echo -n "please input filename >:"
read  filename 
echo "filename=$filename"

if ! [ -e $filename ]  # 文件不存在则报错  
then 
    echo "file not existed"
    exit 1
fi 

if [ -b $filename ]   # 块设备文件 
then 
    echo "block"
elif test -c $filename  # 字符设备文件
then 
    echo "character"
elif [ -d $filename ] #目录 
then 
    echo "directory"
elif [ -h $filename ]  # 符号链接
then 
    echo "link"
elif [ -f $filename ] # 普通文件
then 
    echo "regular"
elif [ -S $filename ]  # socket文件 
then 
    echo "socket"
elif [ -p $filename ]  # pipe文件 
then 
    echo "pipe"
fi


if [ -r $filename ]  # 可读 
then 
    echo "read"
fi

if [ -w $filename ]  # 可写 
then 
    echo "write"
fi

if [ -x $filename ]  # 可执行 
then 
    echo "exec"
fi
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./10-test-file.sh 
please input filename >:/
filename=/
directory
read
exec
linux@ubuntu:~/work/02-linuxbase$ ./10-test-file.sh 
please input filename >:09-test-file.sh
filename=09-test-file.sh
regular
read
write
exec
linux@ubuntu:~/work/02-linuxbase$ 
6. 条件语句 if … then …fi

语法结构:

if    表达式
then  
		命令表
fi     

如果表达式为真, 则执行命令表中的命令; 否则退出if语句, 即执行fi后面的语句。

if和fi是条件语句的语句括号, 必须成对使用;

命令表中的命令可以是一条, 也可以是若干条。

7. 条件语句 if…then…else…fi

语法结构为:

if      表达式
then 
	命令表1
else  
	命令表2
fi

如果表达式为真, 则执行命令表1中的命令;

否则执行命令表2中的语句.

8. 条件语句 if…then…elif … then … else…fi

语法结构为:

if     表达式1
then   
	命令表1
elif   表达式2
then   
	命令表2 
else   
	命令表3 
fi

如果表达式1为真, 则执行命令表1中的命令, 再退出if语句;

否则执行命令表2中的语句, 再退出if语句.

9. 多路分支语句 case…esac

多路分支语句case用于多重条件测试, 语法结构清晰自然. 其语法为:

 case   字符串变量   in
            模式1)
                       命令表1
                        ;;   # 这个分号不能少 
            模式2)
                       命令表2
                        ;;
             ……
            模式n)
                       命令表n
                        ;;
             *)
            ;;

 esac

实例31

  • 输入成绩的水平(A/B/C/D/E), 转换成成绩的范围
  • 源文件
11-case.sh 
  • 源代码
#! /bin/bash



echo -n "please input your level(A/B/C/D/E) >:"
read level 
echo "level = $level"


case  $level  in 
    "A")
        echo "90 =< score <=100"
        ;;
    "B")
        echo "80 =< score < 90"
        ;;
    "C")
        echo "70 =< score < 80"
        ;;
    "D")
        echo "60 =< score < 70"
        ;;
    "E")
        echo " 0 =< score < 60"
        ;;
    *)
        ;;
esac


  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:A
level = A
90 =< score <=100
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:B
level = B
80 =< score < 90
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:C
level = C
70 =< score < 80
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:D
level = D
60 =< score < 70
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:E
level = E
 0 =< score < 60
linux@ubuntu:~/work/02-linuxbase$ ./11-case.sh 
please input your level(A/B/C/D/E) >:8
level = 8
linux@ubuntu:~/work/02-linuxbase$ 
10. for…do…done

当循环次数已知或确定时, 使用for循环语句来多次执行一条或一组命令。 循环体由语句括号do和done来限定。

格式为:

for  变量名  in  单词表
do
  命令表
done

变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令. 循环次数由单词表中的单词数确定. 命令表中的命令可以是一条, 也可以是由分号或换行符分开的多条。

实例32

  • 源文件
12-for.sh 
  • 源代码
#! /bin/bash


mylist=`ls`

if ! [ -e hello ]  # 判断当前目录下, hello目录是否存在
then 
    mkdir hello 
fi 

for file in $mylist 
do 
    if [ $file != hello ]    # 如果文件名不是hello , 就复制, 是就不复制了
    then 
        cp $file hello 
    fi 

done 
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./12-for.sh 
linux@ubuntu:~/work/02-linuxbase$ ls
01-hello.sh   03-huanjing.sh  05-expr.sh      07-test-yes-no.sh  09-test-file.sh  11-case.sh  hello
02-weizhi.sh  04-read.sh      06-test-str.sh  08-test-numer.sh   10-test-file.sh  12-for.sh
linux@ubuntu:~/work/02-linuxbase$ ls hello/
01-hello.sh   03-huanjing.sh  05-expr.sh      07-test-yes-no.sh  09-test-file.sh  11-case.sh
02-weizhi.sh  04-read.sh      06-test-str.sh  08-test-numer.sh   10-test-file.sh  12-for.sh
linux@ubuntu:~/work/02-linuxbase$ 
11. 循环语句 while…do…done

语法结构为:

while     命令或表达式
do
	命令表
done

while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环。

while语句的退出状态为命令表中被执行的最后一条命令的退出状态。

实例32:

  • 计算1+2+3+4+…+100 之和
  • 源文件
13-while.sh 
  • 源代码
#! /bin/bash


i=0
sum=0
while  [ $i -lt 100 ] 
do 
    i=`expr $i + 1 `    # i = i + 1 
    echo "i=$i"
    sum=`expr $sum + $i `
done
echo "sum=$sum"
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./13-while.sh 
i=1
i=2
i=3
i=4
i=5
i=6
...
i=89
i=90
i=91
i=92
i=93
i=94
i=95
i=96
i=97
i=98
i=99
i=100
sum=5050
linux@ubuntu:~/work/02-linuxbase$
12. 循环语句 until…do…done

语法结构为:

until   命令或表达式
do
	命令表
done

until循环与while循环的功能相似, 所不同的是只有当测试的命令或表达式的值是假时, 才执行循环体中的命令表, 否则退出循环. 这一点与while命令正好相反.

实例34

  • 计算1+2+3+4+…+100 之和
  • 源文件
14-until.sh
  • 源代码
#! /bin/bash

i=0
sum=0
until ! [ $i -lt 100 ] 
do 
    i=`expr $i + 1 `    # i = i + 1 
    echo "i=$i"
    sum=`expr $sum + $i `
done
echo "sum=$sum"
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./14-until.sh 
i=1
i=2
i=3
i=4
i=5
i=6
...
i=90
i=91
i=92
i=93
i=94
i=95
i=96
i=97
i=98
i=99
i=100
sum=5050
linux@ubuntu:~/work/02-linuxbase$ 
13. break 和 continue

break n 则跳出n层;

continue语句则马上转到最近一层循环语句的下一轮循环上,

continue n则转到最近n层循环语句的下一轮循环上.

实例35

  • 计算一天有多少秒
  • 源文件
15-break-continue.sh
  • 源代码
#! /bin/bash

sec=0
min=0
hour=0
count_sec=0
while  true 
do 
    echo "HH:MM:SS -> $hour:$min:$sec"
    count_sec=`expr $count_sec + 1`
    sec=`expr $sec + 1`
    if [ $sec -lt 60 ]
    then 
        continue 
    fi 
    sec=0
    min=`expr $min + 1`
    if [ $min -lt 60 ]
    then 
        continue 
    fi 
    min=0
    hour=`expr $hour + 1`
    if [ $hour -lt 24 ]
    then 
        continue 
    fi 
    hour=0
    break

done  
echo "count_sec=$count_sec"
  • 运行结果
...
HH:MM:SS -> 23:59:46
HH:MM:SS -> 23:59:47
HH:MM:SS -> 23:59:48
HH:MM:SS -> 23:59:49
HH:MM:SS -> 23:59:50
HH:MM:SS -> 23:59:51
HH:MM:SS -> 23:59:52
HH:MM:SS -> 23:59:53
HH:MM:SS -> 23:59:54
HH:MM:SS -> 23:59:55
HH:MM:SS -> 23:59:56
HH:MM:SS -> 23:59:57
HH:MM:SS -> 23:59:58
HH:MM:SS -> 23:59:59
count_sec=86400
linux@ubuntu:~/work/02-linuxbase$ 

14.5 shell 函数

1. 函数

​ 在shell程序中, 常常把完成固定功能、且多次使用的一组命令(语句)封装在一个函数里,每当要使用该功能时只需调用该函数名即可。

​ 函数在调用前必须先定义,即在顺序上函数说明必须放在调用程序的前面。

​ 调用程序可传递参数给函数, 函数可用return语句把运行结果返回给调用程序。

​ 函数只在当前shell中起作用, 不能输出到子Shell中。

函数定义格式:

方式一:

function_name ( )
{
            command1
            ……
            commandn
}

方式二 :

function   function_name ( )
{
            command1
            ……
            commandn
}

实例35

  • 使用函数计算2个数的 加减乘除求余
  • 源文件
16-func.sh 
  • 源代码
#! /bin/bash


add()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 + $2`
    return $ret 
}
sub()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 - $2`
    return $ret 
}

mul()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 \* $2`
    return $ret 
}
div()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 / $2`
    return $ret 
}
yu()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 % $2`
    return $ret 
}



echo -n "please input 2 number >:"
read n1 n2 
echo "n1=$n1 , n2=$n2"

if [ -z $n1 ] || [ -z $n2 ]
then 
    echo "n1 or n2 empty"
fi 

add $n1 $n2     
# 位置变量
# $0 = add 
# $1 = $n1 
# $2 = $n2
# 函数的返回值 通过$? 获取 
echo "$n1 + $n2 = $? "

sub $n1 $n2     
echo "$n1 - $n2 = $? "

mul $n1 $n2     
echo "$n1 * $n2 = $? "

div $n1 $n2     
echo "$n1 / $n2 = $? "

yu $n1 $n2     
echo "$n1 % $n2 = $? "

  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./16-func.sh 
please input 2 number >:10 4
n1=10 , n2=4
1=10
2=4
10 + 4 = 14 
1=10
2=4
10 - 4 = 6 
1=10
2=4
10 * 4 = 40 
1=10
2=4
10 / 4 = 2 
1=10
2=4
10 % 4 = 2 
linux@ubuntu:~/work/02-linuxbase$ 
2. 局部变量与全局变量

声明局部变量的格式:
local variable_name =value
全局作用域:在脚本的其他任何地方都能够访问该变量。
variable_name =value

实例36

  • 全局变量和局部变量的使用
  • 源文件
17-global.sh 
  • 源代码
#! /bin/bash

number1=200    # 全局变量

add()
{
    local number2=100   # 局部变量 
    echo "add:number1=$number1"
    echo "add:number2=$number2"

    ret=`expr $1 + $2`
    return $ret 
}



echo "number1=$number1"
echo "number2=$number2"

add  1 2 

  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./17-global.sh 
number1=200
number2=
add:number1=200
add:number2=100
linux@ubuntu:~/work/02-linuxbase$ 

14.6 shell 调试方法

分析输出的错误信息。

通过在脚本中加入调试语句,输出调试信息来辅助诊断错误。

功能:set -x , set +x 跟踪程序的每一步的执行结果

实例37

  • 源文件
18-debug.sh 
  • 源代码
#! /bin/bash

set -x 
add()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 + $2`
    return $ret 
}
sub()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 - $2`
    return $ret 
}

mul()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 \* $2`
    return $ret 
}
div()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 / $2`
    return $ret 
}
yu()
{
    echo "1=$1"
    echo "2=$2"
    ret=`expr $1 % $2`
    return $ret 
}






echo -n "please input 2 number >:"
read n1 n2 
echo "n1=$n1 , n2=$n2"

if [ -z $n1 ] || [ -z $n2 ]
then 
    echo "n1 or n2 empty"
fi 

add $n1 $n2     
# 位置变量
# $0 = add 
# $1 = $n1 
# $2 = $n2
# 函数的返回值 通过$? 获取 
echo "$n1 + $n2 = $? "

sub $n1 $n2     
echo "$n1 - $n2 = $? "

mul $n1 $n2     
echo "$n1 * $n2 = $? "

div $n1 $n2     
echo "$n1 / $n2 = $? "

yu $n1 $n2     
echo "$n1 % $n2 = $? "


set +x 
  • 运行结果
linux@ubuntu:~/work/02-linuxbase$ ./18-debug.sh 
+ echo -n 'please input 2 number >:'
please input 2 number >:+ read n1 n2
1 4
+ echo 'n1=1 , n2=4'
n1=1 , n2=4
+ '[' -z 1 ']'
+ '[' -z 4 ']'
+ add 1 4
+ echo 1=1
1=1
+ echo 2=4
2=4
++ expr 1 + 4
+ ret=5
+ return 5
+ echo '1 + 4 = 5 '
1 + 4 = 5 
+ sub 1 4
+ echo 1=1
1=1
+ echo 2=4
2=4
++ expr 1 - 4
+ ret=-3
+ return -3
+ echo '1 - 4 = 253 '
1 - 4 = 253 
+ mul 1 4
+ echo 1=1
1=1
+ echo 2=4
2=4
++ expr 1 '*' 4
+ ret=4
+ return 4
+ echo '1 * 4 = 4 '
1 * 4 = 4 
+ div 1 4
+ echo 1=1
1=1
+ echo 2=4
2=4
++ expr 1 / 4
+ ret=0
+ return 0
+ echo '1 / 4 = 0 '
1 / 4 = 0 
+ yu 1 4
+ echo 1=1
1=1
+ echo 2=4
2=4
++ expr 1 % 4
+ ret=1
+ return 1
+ echo '1 % 4 = 1 '
1 % 4 = 1 
+ set +x
linux@ubuntu:~/work/02-linuxbase$ 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值