鸟哥的linux私房菜——第十二章学习(Shell Scripts)
第十二章 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....
【重点回顾】
- shell script 是利用 shell 的功能所写的一个“程序 (program)”,这个程序是使用纯文本文件,将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的;
- shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了,因为 Shell scripts 的速度较慢,且使用的CPU 资源较多,造成主机资源的分配不良;
- 在 Shell script 的文件中,指令的执行是从上而下、从左而右的分析与执行;
- shell script 的执行,至少需要有 r 的权限,若需要直接指令下达,则需要拥有 r 与 x 的权限;
- 良好的程序撰写习惯中,第一行要宣告 shell (#!/bin/bash) ,第二行以后则宣告程序用途、版本、作者等;
- 对谈式脚本可用 read 指令达成;
- 要创建每次执行脚本都有不同结果的数据,可使用 date 指令利用日期达成;
- script 的执行若以 source 来执行时,代表在父程序的 bash 内执行之意!
- 若需要进行判断式,可使用 test 或中括号 ( [] ) 来处理;
- 在 script 内,$0, $1, $2..., $@ 是有特殊意义的!
- 条件判断式可使用 if...then 来判断,若是固定变量内容的情况下,可使用 case $var in ... esac 来处理;
- 循环主要分为不定循环 (while, until) 以及固定循环 (for) ,配合 do, done 来达成所需任务!
- 我们可使用 sh -x script.sh 来进行程序的 debug。
Over...
鸟哥的linux私房菜——第十二章学习(Shell Scripts)的更多相关文章
- 鸟哥的linux私房菜——第十六章学习(程序管理与 SELinux 初探)
第十六章.程序管理与 SE Linux 初探 在 Linux 系统当中:"触发任何一个事件时,系统都会将他定义成为一个程序,并且给予这个程序一个 ID ,称为 PID,同时依据启发这个程序的 ...
- 鸟哥的Linux私房菜——第十二章:档案的压缩与打包
视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...
- 鸟哥的Linux私房菜——第十九章:例行命令的建立
视频链接:http://www.bilibili.com/video/av11008859/ 1. 什么是例行性命令 (分为两种,一种是周期性的,一种是突发性的)1.1 Linux 工作排程的种类: ...
- 鸟哥的Linux私房菜——第十四章:Bash Shell
视频链接:http://www.bilibili.com/video/av10094012/ 本章目录: 1. Bash shell1.1 什么是 shell ? (我们通过shell与Kernel核 ...
- 鸟哥的Linux私房菜——第十六章:学习Shell Scripts
视频链接:http://www.bilibili.com/video/av10565321/ 1. 什么是 Shell Script (shell写的脚本)1.1 干嘛学习 shell s ...
- 鸟哥的Linux私房菜——第十五章:正规表示法
视频链接 B站:http://www.bilibili.com/video/av10364761/ 目录如下 1. 前言:2. 基础正规表示法:2.1 以 grep 撷取字符串 (grep -iv ...
- 鸟哥的Linux私房菜笔记第四章
前言 对着<鸟哥的Linux私房菜-基础版>做了简化笔记.不想让自己知其然而不知其所然.所以写个博客让自己好好巩固一下,当然不可能把书中的内容全部写下来.在这里就简化一点把命令写下来. 让 ...
- 鸟哥的Linux私房菜笔记第六章(二)
文件内容查询 直接查询文件内容 查阅一个文件的内容可以使用指令cat/tac/nl. # [cat|tac|nl] 文件 区别: 1.cat是直接把文件内容输出到屏幕上,并且从第一行开始输出到末行 2 ...
- 鸟哥的Linux私房菜 第十八章、认识系统服务 (daemons)
什么是 daemon 与服务 (service) Linux Daemon (守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些事件.它不需要用户输入就能运行 ...
随机推荐
- ios获取缓存文件的大小并清除缓存
移动应用在处理网络资源时,一般都会做离线缓存处理,其中以图片缓存最为典型,其中很流行的离线缓存框架为SDWebImage. 但是,离线缓存会占用手机存储空间,所以缓存清理功能基本成为资讯.购物.阅读类 ...
- ts类与修饰符
最近在用egret做游戏,就接触到了ts,刚开始的时候觉得类挺难的,毕竟大多数的JavaScript工程师工作中不怎么需要用到这个,但是学起来就不愿意撒手了,真香! typescript其实是es6的 ...
- DSL是什么?Elasticsearch的Query DSL又是什么?
1.DSL简介 DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言.而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证(备注:G ...
- canvas星空背景特效+CSS旋转相册学习
今天在看帖子的时候,看到了个有趣的css旋转相册,刚好之前做了一个星空背景dome,这里给大家分享下代码: 旋转相册参考:https://blog.csdn.net/gitchatxiaomi/art ...
- 基于Python的接口自动化-unittest测试框架和ddt数据驱动
引言 在编写接口自动化用例时,我们一般针对一个接口建立一个.py文件,一条接口测试用例封装为一个函数(方法),但是在批量执行的过程中,如果其中一条出错,后面的用例就无法执行,还有在运行大量的接口测试用 ...
- JavaScript常用API
JavaScript常用API 节点属性 文档节点 事件监听.一出事件 获取元素方法
- SQL性能优化汇总
SQL效率低下也是导致性能差的一个非常重要的原因,可以通过查看执行计划看SQL慢在哪里,一般情况,SQL效率低下原因主要有: 类别 子类 表达式或描述 原因 索引 未建索引 无 产生全表扫描 未利 ...
- MySQL调优性能监控之performance schema
一.performance_schema的介绍 performance:性能 schema:图(表)示,以大纲或模型的形式表示计划或理论. MySQL的performance schema 用于监控M ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- centos7 快速搭建redis集群环境
本文主要是记录一下快速搭建redis集群环境的方式. 环境简介:centos 7 + redis-3.2.4 本次用两个服务6个节点来搭建:192.168.116.120 和 192.168.1 ...