第十二章  Shell Scripts

1.0)、什么是shell scripts?

script 是“脚本、剧本”的意思。整句话是说, shell script 是针对 shell 所写的“剧本!”

shell script 是利用 shell 的功能所写的一个“程序 (program)”,这个程序是使用纯文本文件,将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。

就像是早期 DOS 年代的批处理文件 (.bat) ,最简单的功能就是将许多指令汇整写在一起,不需要编译即可执行。

1.1)、shell scripts优点

l 自动化管理的重要依据

l 追踪与管理系统的重要工作

l 简单入侵侦测功能

l 连续指令单一化

l 简易的数据处理

l 跨平台支持与学习历程较短

2.0)、第一支script 的撰写与执行

注意事项:

1. 指令的执行是从上而下、从左而右的分析与执行;

2. 指令的下达就如同第四章内提到的: 指令、选项与参数间的多个空白都会被忽略掉;

3. 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;

4. 如果读取到一个 Enter 符号 (CR) ,就尝试开始执行该行 (或该串) 命令;

5. 至于如果一行的内容太多,则可以使用“ \[Enter] ”来延伸至下一行;

6. “ # ”可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!

假设shell.sh文件在/home/dmtsai/目录下,那么执行sh文件方式:

l 直接指令下达:shell.sh 文件必须要具备可读与可执行 (rx) 的权限,然后:

  • 绝对路径:使用 /home/dmtsai/<filename>.sh 来下达指令;
  • 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来执行;
  • 变量“PATH”功能:将 shell.sh 放在 PATH 指定的目录内,例如: “ ~/bin/ ”。

l 以bash程序来执行:通过“bash <filename>.sh”或者“sh <filename>.sh”

解析:

因为 /bin/sh 其实就是 /bin/bash (链接文件),使用 sh shell.sh 亦即告诉系统,我想要直接以bash 的功能来执行 shell.sh 这个文件内的相关指令的意思,

【第一支script】

[dmtsai@study ~]$ mkdir bin; cd bin
[dmtsai@study bin]$ vim hello.sh
#!/bin/bash
# Program:
# This program shows "Hello World!" in your screen.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello World! \a \n"
exit 0

注解:

1、第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称;

2、整个 script 当中,除了第一行的“ #! ”是用来宣告 shell 的之外,其他的 # 都是“注解”用途;

3、主要环境变量的宣告PATH;

4、主要程序部分,就是echo那一行;

5、执行成果告知:讨论一个指令的执行成功与否,可以使用 $? 这个变量来观察(如接着使用echo $? 即可查询命令是否执行成功),在srcipt中我们也可以利用 exit 这个指令来让程序中断,并且回传一个数值给系统,如exit n(n是一个数字)。

2.1)、简单的数值运算:+,-,*,、,%

运算时,可使用:echo $(( 运算内容 ))

小数点:| bc,是“basic calculator”的缩写。

计算PI值:

[dmtsai@study bin]$ vim cal_pi.sh
#!/bin/bash
# Program:
# User input a scale number to calculate pi number.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "This program will calculate pi value. \n"
echo -e "You should input a float number to calculate pi value.\n"
read -p "The scale number (10~10000) ? " checking
num=${checking:-"10"} # 开始判断有否有输入数值
echo -e "Starting calcuate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq

注释:

tan 45°  =1; 45°也可以写作 π/4,四分之派。所以arctan 1(echo中的a(1))的值也就是π/4,乘以4当然就是π的值。

2.2)、script的执行方式差异(source, sh script, ./script)

l 利用直接执行的方式来执行 script

当子程序完成后,在子程序内的各项变量或动作将会结束而不会传回到父程序中。

意思就是:当你使用直接执行的方法来处理时,系统会给予一支新的 bash 让我们来执行 showname.sh 里面的指令,因此你的 firstname, lastname 等变量其实是在下图中的子程序 bash 内执行的。 当 showname.sh 执行完毕后,子程序 bash 内的所有数据便被移除,因此上表的练习中,在父程序下面 echo ${firstname} 时, 就看不到任何东西了。类似于局部变量。

l 利用 source 来执行脚本:在父程序中执行

showname.sh 会在父程序中执行的,因此各项动作都会在原本的 bash 内生效。

2.3)、善用判断(test, &&, ||, [])

l test, &&, ||

例子:检查 /dmtsai 是否存在时,使用:

[dmtsai@study ~]$ test -e /dmtsai && echo "exist" || echo "Not exist"
Not exist <==结果显示不存在啊!

l []:中括号

作为判断式时,必须要注意中括号的两端需要有空白字符来分隔。

注意:

  • 在中括号 [] 内的每个元件都需要有空白键来分隔;
  • 在中括号内的变量,最好都以双引号括号起来;
  • 在中括号内的常数,最好都以单或双引号括号起来。

如:判断两个字符串是否相等:

[dmtsai@study ~]$ name="VBird Tsai"
[dmtsai@study ~]$ [ ${name} == "VBird" ]
bash: [: too many arguments

原因就是${name}没有用双引号扩住。

所以上面解析式会变成:[ VBird Tsai == "VBird" ]

但是我们期望的是[ "VBird Tsai" == "VBird" ],所以就需要加上引号了。

另:中括号比较常用在条件判断式 if ..... then ..... fi 的情况中。

【案例:提示输入交互判断】

[dmtsai@study bin]$ vim ans_yn.sh
#!/bin/bash
# Program:
# This program shows the user's choice
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input (Y/N): " yn
[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK, continue" && exit 0
[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "Oh, interrupt!" && exit 0
echo "I don't know what your choice is" && exit 0

注解:

1、由于输入正确 (Yes) 的方法有大小写之分,不论输入大写 Y 或小写 y 都是可以的,此时判断式内就得要有两个判断才行!

2、这里使用 -o (或) 链接两个判断。不能用“||”。

l Shell Script 的默认变量($0, $1...)

read 功能的问题是你得要手动由键盘输入一些判断式。

通过指令后面接参数, 那么一个指令就能够处理完毕而不需要手动再次输入一些变量行为。

/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4
  • $# :代表后接的参数“个数”,以上表为例这里显示为“ 4 ”;
  • $@ :代表“ "$1" "$2" "$3" "$4" ”之意,每个变量是独立的(用双引号括起来);
  • $* :代表“ "$1c$2c$3c$4" ”,其中 c 为分隔字符,默认为空白键, 所以本例中代表“ "$1 $2 $3 $4" ”之意。

2.4)、条件判断式(if...then, case...esac, function)

l if...then

if [ 条件判断式 ]; then
当条件判断式成立时,可以进行的指令工作内容;
fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意!

&& 代表 AND ;

|| 代表 or ;

所以:

[ "${yn}" == "Y" -o "${yn}" == "y" ]
上式可替换为
[ "${yn}" == "Y" ] || [ "${yn}" == "y" ]

多重判断:

# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况执行
if [ 条件判断式一 ]; then <==【if和[之间有空格】
当条件判断式一成立时,可以进行的指令工作内容;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可以进行的指令工作内容;
else
当条件判断式一与二均不成立时,可以进行的指令工作内容;
fi

l case...esac

[dmtsai@study bin]$ vim hello-3.sh
#!/bin/bash
# Program:
# Show "Hello" from $1.... by using case .... esac
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
case ${1} in
"hello")
echo "Hello, how are you ?"
;;
"")
echo "You MUST input parameters, ex> {${0} someword}"
;;
*) # 其实就相当于万用字符,0~无穷多个任意字符之意!
echo "Usage ${0} {hello}"
;;
esac

l function

[dmtsai@study bin]$ vim show123-3.sh
#!/bin/bash
# Program:
# Use function to repeat information.
# History:
# 2015/07/17 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function printit(){
  echo "Your choice is ${1}" # 这个 $1 必须要参考下面指令的下达
}
echo "This program will print your selection !"
case ${1} in
  "one")
    printit 1 # 请注意, printit 指令后面还有接参数!
    ;;
  "two")
    printit 2
    ;;
  "three")
    printit 3
    ;;
  *)
    echo "Usage ${0} {one|two|three}"
    ;;
esac

输入“ sh show123-3.sh one ”就会出现“ Your choice is 1 ”,“ printit 1 ”中那个 1 就会成为 function 当中的 $1 。

function 也是拥有内置变量的~他的内置变量与 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来取代。

特别注意的是,“ function fname() { 程序段 } ”内的 $0, $1... 等等与 shell script 的 $0 是不同的。

l 常见的port与网络服务关系:

80: WWW

22: ssh

21: ftp

25: mail

111: RPC(远端程序调用)

631: CUPS(打印服务功能)

2.5)、循环(loop)

循环可以不断的执行某个程序段落,直到使用者设置的条件达成为止。

循环又分为不定循环和固定循环。

l 不定循环:while do done, until do done

  • while do done
while [ condition ] <==中括号内的状态就是判断式【while和[之间有空格】
do <==do 是循环的开始!
程序段落
done <==done 是循环的结束

例子:

[dmtsai@study bin]$ vim yes_to_stop.sh
#!/bin/bash
# Program:
# Repeat question until user input correct answer.
# History:
# 2015/07/17 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
while [ "${yn}" != "yes" -a "${yn}" != "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."
  • until do done

接上述例子:

[dmtsai@study bin]$ vim yes_to_stop-2.sh
#!/bin/bash
# Program:
# Repeat question until user input correct answer.
# History:
# 2015/07/17 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
until [ "${yn}" == "yes" -o "${yn}" == "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."

注:-a 表示且的意思,-o 表示或的意思。

【举例:计算1--100的和】

[dmtsai@study bin]$ vim cal_1_100.sh
#!/bin/bash
# Program:
# Repeat question until user input correct answer.
# History:
# 2015/07/17 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH echo "this program is to calculate from 1 to 100."
read -p "Now do u want to start(y/n)?" yn
sum=0;
if [ "${yn}" == "y" -o "${yn}" == "Y" ]; then
i=0;
while [ "${i}" -le "100" ] # 可换成for i in $(seq 1 100)
do
echo " i = ${i} "
sum=$(( $sum+$i ))
i=$(( $i+1 ))
done
echo "1+2+...+100 = ${sum}"
elif [ "${yn}" == "n" -o "${yn}" == "N" ]; then
echo "U dont want to calculate,if u want, plz retry and input y."
else
echo "I dont your choose."
fi
exit 0

上述中的while [...]这一行还可以换成for i in $(seq 1 100)

seq表示连续的。其缩写为{1..100} 来取代 $(seq 1 100)

l 固定循环for...do...done

for的用法有两种:

  • 第一种:
for var in con1 con2 con3 ...
do
程序段
done

注:

1. 第一次循环时, $var 的内容为 con1 ;

2. 第二次循环时, $var 的内容为 con2 ;

3. 第三次循环时, $var 的内容为 con3 ;

依次循环。

  • 第二种:
for(( 初始值; 限制值; 执行步阶))  <==【for和(之间可以有空格,也可没有】
do
程序段
done

1.初始值:某个变量在循环当中的起始值,直接以类似 i=1 设置好;

2.限制值:当变量的值在这个限制值的范围内,就继续进行循环。例如 i<=100;

3.执行步阶:每作一次循环时,变量的变化量。例如 i=i+1,亦可写成i++。

除了使用大小等于符号之外,还有如下符号表示:

-eq

等于

-ne

不等于

-gt

大于

-lt

小于

-ge

大于等于

-le

小于等于

注意:

语法问题:

if [ 条件判断式一 ]; then  <==【if和[之间必须有空格】

while [ condition ] <==中括号内的状态就是判断式【while和[之间必须有空格】

for(( 初始值; 限制值; 执行步阶))  <==【for和(之间可以有空格,也可没有】

3.0)、追踪(debug)

debug

[dmtsai@study ~]$ sh [-nvx] scripts.sh
选项与参数:
-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!
范例一:测试 dir_perm.sh 有无语法的问题?
[dmtsai@study ~]$ sh -n dir_perm.sh
# 若语法没有问题,则不会显示任何信息!
范例二:将 show_animal.sh 的执行过程全部列出来~
[dmtsai@study ~]$ sh -x show_animal.sh
+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin
+ export PATH
+ for animal in dog cat elephant
+ echo 'There are dogs.... '
There are dogs....
+ for animal in dog cat elephant
+ echo 'There are cats.... '
There are cats....
+ for animal in dog cat elephant
+ echo 'There are elephants.... '
There are elephants....

【重点回顾】

  1. shell script 是利用 shell 的功能所写的一个“程序 (program)”,这个程序是使用纯文本文件,将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的;
  2. shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为 Shell scripts 的速度较慢,且使用的CPU 资源较多,造成主机资源的分配不良;
  3. 在 Shell script 的文件中,指令的执行是从上而下、从左而右的分析与执行;
  4. shell script 的执行,至少需要有 r 的权限,若需要直接指令下达,则需要拥有 r 与 x 的权限;
  5. 良好的程序撰写习惯中,第一行要宣告 shell (#!/bin/bash) ,第二行以后则宣告程序用途、版本、作者等;
  6. 对谈式脚本可用 read 指令达成;
  7. 要创建每次执行脚本都有不同结果的数据,可使用 date 指令利用日期达成;
  8. script 的执行若以 source 来执行时,代表在父程序的 bash 内执行之意!
  9. 若需要进行判断式,可使用 test 或中括号 ( [] ) 来处理;
  10. 在 script 内,$0, $1, $2..., $@ 是有特殊意义的!
  11. 条件判断式可使用 if...then 来判断,若是固定变量内容的情况下,可使用 case $var in ... esac 来处理;
  12. 循环主要分为不定循环 (while, until) 以及固定循环 (for) ,配合 do, done 来达成所需任务!
  13. 我们可使用 sh -x script.sh 来进行程序的 debug。

Over...

鸟哥的linux私房菜——第十二章学习(Shell Scripts)的更多相关文章

  1. 鸟哥的linux私房菜——第十六章学习(程序管理与 SELinux 初探)

    第十六章.程序管理与 SE Linux 初探 在 Linux 系统当中:"触发任何一个事件时,系统都会将他定义成为一个程序,并且给予这个程序一个 ID ,称为 PID,同时依据启发这个程序的 ...

  2. 鸟哥的Linux私房菜——第十二章:档案的压缩与打包

    视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...

  3. 鸟哥的Linux私房菜——第十九章:例行命令的建立

    视频链接:http://www.bilibili.com/video/av11008859/ 1. 什么是例行性命令 (分为两种,一种是周期性的,一种是突发性的)1.1 Linux 工作排程的种类: ...

  4. 鸟哥的Linux私房菜——第十四章:Bash Shell

    视频链接:http://www.bilibili.com/video/av10094012/ 本章目录: 1. Bash shell1.1 什么是 shell ? (我们通过shell与Kernel核 ...

  5. 鸟哥的Linux私房菜——第十六章:学习Shell Scripts

    视频链接:http://www.bilibili.com/video/av10565321/ 1. 什么是 Shell Script       (shell写的脚本)1.1 干嘛学习 shell s ...

  6. 鸟哥的Linux私房菜——第十五章:正规表示法

    视频链接 B站:http://www.bilibili.com/video/av10364761/ 目录如下 1. 前言:2. 基础正规表示法:2.1 以 grep 撷取字符串 (grep -iv   ...

  7. 鸟哥的Linux私房菜笔记第四章

    前言 对着<鸟哥的Linux私房菜-基础版>做了简化笔记.不想让自己知其然而不知其所然.所以写个博客让自己好好巩固一下,当然不可能把书中的内容全部写下来.在这里就简化一点把命令写下来. 让 ...

  8. 鸟哥的Linux私房菜笔记第六章(二)

    文件内容查询 直接查询文件内容 查阅一个文件的内容可以使用指令cat/tac/nl. # [cat|tac|nl] 文件 区别: 1.cat是直接把文件内容输出到屏幕上,并且从第一行开始输出到末行 2 ...

  9. 鸟哥的Linux私房菜 第十八章、认识系统服务 (daemons)

    什么是 daemon 与服务 (service) Linux Daemon (守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些事件.它不需要用户输入就能运行 ...

随机推荐

  1. ios获取缓存文件的大小并清除缓存

    移动应用在处理网络资源时,一般都会做离线缓存处理,其中以图片缓存最为典型,其中很流行的离线缓存框架为SDWebImage. 但是,离线缓存会占用手机存储空间,所以缓存清理功能基本成为资讯.购物.阅读类 ...

  2. ts类与修饰符

    最近在用egret做游戏,就接触到了ts,刚开始的时候觉得类挺难的,毕竟大多数的JavaScript工程师工作中不怎么需要用到这个,但是学起来就不愿意撒手了,真香! typescript其实是es6的 ...

  3. DSL是什么?Elasticsearch的Query DSL又是什么?

    1.DSL简介 DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言.而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证(备注:G ...

  4. canvas星空背景特效+CSS旋转相册学习

    今天在看帖子的时候,看到了个有趣的css旋转相册,刚好之前做了一个星空背景dome,这里给大家分享下代码: 旋转相册参考:https://blog.csdn.net/gitchatxiaomi/art ...

  5. 基于Python的接口自动化-unittest测试框架和ddt数据驱动

    引言 在编写接口自动化用例时,我们一般针对一个接口建立一个.py文件,一条接口测试用例封装为一个函数(方法),但是在批量执行的过程中,如果其中一条出错,后面的用例就无法执行,还有在运行大量的接口测试用 ...

  6. JavaScript常用API

    JavaScript常用API 节点属性 文档节点 事件监听.一出事件 获取元素方法

  7. SQL性能优化汇总

    SQL效率低下也是导致性能差的一个非常重要的原因,可以通过查看执行计划看SQL慢在哪里,一般情况,SQL效率低下原因主要有:   类别 子类 表达式或描述 原因 索引 未建索引 无 产生全表扫描 未利 ...

  8. MySQL调优性能监控之performance schema

    一.performance_schema的介绍 performance:性能 schema:图(表)示,以大纲或模型的形式表示计划或理论. MySQL的performance schema 用于监控M ...

  9. 十:SpringBoot-配置AOP切面编程,解决日志记录业务

    SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...

  10. centos7 快速搭建redis集群环境

    本文主要是记录一下快速搭建redis集群环境的方式. 环境简介:centos 7  + redis-3.2.4 本次用两个服务6个节点来搭建:192.168.116.120  和  192.168.1 ...