脚本文件格式:
第一行,顶格:#!/bin/bash
注释信息:#
代码注释:
缩进,适度添加空白行
语言:编程语法格式,库,算法和数据结构;
编程思想:
问题空间 à解空间
变量:
局部变量
本地变量
环境变量
位置参数变量
特殊变量
数据类型:字符型、数值型
弱类型:字符型;
Bash中的算术运算:
+,-,*,/,%,**
实现算术运算:
1)let var=算术表达式;
2)var=$[算术表达式]
3)var=$((算术表达式))
4)var=$(expr arg1 arg2 arg3…)
乘法符号在有些场景中需要转义;
Bash有內建的随机数生成器;$RANDOM
增强型赋值:
+=,-=,*=,/=,%=
let varOPERvalue
例如:let count+=1
自增,自减:
let var+=1
let var++
let var-=1
let var—
练习1:写一个脚本,计算/etc/passwd文件的第10个用户和第20个用户的ID之和;
练习2:写一个脚本,传递两个文件路径作为参数脚本,计算这两个文件中所有空白行之和;
条件测试:
判断某需求是否满足,需要由测试机制来实现;
如何编写测试表达式以实现所需的测试:
1)执行命令,并利用命令状态返回值来判断;
0:成功;
1-255:失败;
2)专用的测试表达式需要由测试命令辅助完成测试过程;
测试命令:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
NOTE:expression前后必须有空白字符;
Bash的测试类型:
数值测试:数值比较
-gt:是否大于;
-ge:是否大于等于;
-eq:是否等于;
-ne:是否不等于;
-lt;是否小于;
-le:是否小于等于;
字符串测试:
==:是否等于;
>:是否大于
<:是否小于
!=:是否不等于;
=~:左侧字符串是否能够被右侧的PATTERN所匹配;
Note:此表达式一般用于[[]]中;
-z “string”:测试字符串是否为空,空则真,不空则为假;
-n “string”:测试字符串是否为不空,不空则为真,空则为假;
Note:
1)用于字符串比较时的用到的操作数都应该使用引号;
2)要使用[[]];
文件测试:
存在性测试:
-a FILE
-e FILE
文件的存在性测试,存在则为真,否则则为假;
存在性及类型测试:
-b file:是否存在并且为块设备文件;
-c file:是否存在并且为字符设备文件;
-d file:是否存在并且为目录文件;
-f file:是否存在并且为普通文件;
-h file 或 –L file:是否存在并且为符号链接文件;
-p file:是否存在并且为命名管道文件;
-S file:是否存在并且为套接字文件;
文件权限测试:
-r file:是否存在并且对当前用户可读;
-w file:是否存在并且对当前用户可写;
-x file:是否存在并且对当前用户可执行;
特殊权限测试:
-u file:是否存在并且拥有suid权限;
-g file:是否存在并且拥有sgid权限;
-k file:是否存在并且拥有sticky权限;
文件是否有内容:
-s file:是否有内容;
时间戳:
-N file:文件自从上一次读操作后是否被修改过;
从属关系测试:
-O file:当前用户是否为文件的属主;
-G file:当前用户是否为文件的属组;
双目测试;
File1 –ef file2:file1与file2是否指向同一个文件系统的相同inode的硬连接;
File1 –nt file2:file1是否新于file2;
File1 –ot file2:file1是否旧于file2;
组合条件测试:
逻辑运算:
方式一:
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
! COMMAND
[ -O FILE ] && [ -r file ]
方式二:
EXPRESSION1 –a EXPRESSION2
EXPRESSION1 –o EXPRESSION2
! EXPRESSION
[ -O FILE –a –x FILE ]
练习:将当前主机名称保存至hostName变量中,如果主机名为空,或者为localhost.localdomain,则将其设置为www.claude666.com;
脚本的状态返回值:
默认是脚本中执行的最后一条件命令的状态返回值;
自定义状态退出状态码:
exit [n]:n为自己指定的状态码;
note:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束;
向脚本传递参数:
位置参数变量
myscript.sh argu1 argu2
引用方式:
$1, $2, ..., ${10}, ${11}, ...
轮替:
Shift [n]:位置参数轮替
练习:写一脚本,通过命令传递两个文本文件路径给脚本,计算其空白行数之和;
过程式编程语言的代码执行顺序;
顺序执行:逐条执行;
选择执行;
代码有一个分支;条件满足时才会执行;
两个或以上的分支:只会执行其中一个满足条件的分支;
循环执行;
代码片段(循环体)要执行0、1或多个来回;
选择执行:
单分支的if语句:
if 测试条件;then
代码分支
fi
双分支的if语句:
if 测试条件;then
条件为真时执行的分支
else
条件为假时执行的分支
fi
多分支的if语句
if CONDITION1; then
条件1为真分支
elif CONDITION2; then
条件2为真分支
elif CONDITION3; then
条件3为真分支
...
elif CONDITIONn; then
条件n为真分支
else
所有条件均不满足时的分支
Fi
Note:即便多个条件同时满足,分支只会执行其中的一个,首先测试为“真”
示例1:脚本参数传递一个问文件路径给脚本,判断此文件的类型;
练习:写一个脚本
1)传递一个参数给脚本,此参数为用户名;
2)根据其id号来判断用户类型;
0:管理员
1-999:系统用户
1000+:普通用户
练习:写一个脚本
1)列出如下菜单给用户;
disk) show disks info;
mem) show memory info;
cpu) show cpu info;
*) exit
2)提示用户给出自己的选择,而后显示对应其选择的相应系统信息;
示例2:通过参数传递一个用户名给脚本,此用户不存在时,则添加之,如果存在,显示用户已存在;
练习1:通过命令行给定两个数字,输出其中较大的值;
方法一:
方法二:
练习2:通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;
练习3:通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行;都存在时返回每个文件的行数,并说明其中行数较多的文件;
练习4:写一个脚本完成如下功能;
1)列出当前系统识别到的所有磁盘设备;
2)如磁盘数量为1,则显示其空间使用信息;否则,则显示左后一个磁盘上的空间信息;
在虚拟机再添加一块硬盘重新测试:
Bash脚本编程之用户交互:
read [option]… [name …]
-p ‘PROMPT‘后面跟提示信息,即在输入前打印处提示信息;
-t TIMEOUT 后面跟秒数,意思为输入命令的等待秒数;
bash -n /path/to/some_script
检测脚本中的语法错误
bash -x /path/to/some_script
调试执行
示例1:输入一个磁盘分区,查看是否存在,存在则输出磁盘信息:
示例2:添加用户及设置密码;
循环执行:将一段代码重复执行0、1或多次;
进入条件:条件满足才进入循环;
退出条件:每个循环都应该应该有退出条件,以有机会推出循环;
Bash脚本:
For循环
While循环
Until循环
for循环:
两种格式;
1)遍历列表;
2)控制变量;
遍历列表:
for VARAIBLE in LIST;do
循环体
done
进入条件:只要列表有元素,即可进入循环;
退出条件:列表中的元素遍历完成;
LIST的生成方式:
1)直接给出;
2)整数列表
a){start..end}
b)seq [start [incremtal] last]
3)返回列表的命令;
4)glob
5)变量引用;[email protected],$*
练习:批量添加用户(for)
练习:求100以内所有正整数之和;
练习:判断/var/log目录下的每一个文件的内容类型
练习:
1)分别求100以内所有偶数之和,以及所有奇数之和;
2)计算当前系统上的所有id之和;
3)通过脚本参数传递目录给脚本,而后计算此目录下所有文本文件的行数之和;并说明此类文件的总数;
while循环:
while CONDITION;do
循环体
循环控制变量修正表达式
done
进入条件:CONDITION测试为“真”
退出条件:CONDITION测试为“假”
until循环:
until CONDITION;do
循环体
循环控制变量修正表达式
done
进入条件:CONDITION测试为“假”
退出条件:CONDITION测试为“真”
示例:求100以内所有正整数之和;
方法一:while循环
方法二:until循环;
练习:分别用for,while,until实现
1.分别求100以内所有偶数之和,100以内所有奇数之和;
方法一:for循环
方法二:while循环
方法三:until循环
2.创建10个用户,user101-user110;密码同用户名;
方法一:for循环
方法二:while循环
方法三:until循环
3.打印九九乘法表;
方法一:for循环
方法二:while循环
方法三:until循环
4.打印逆序的九九乘法表;
方法一:for循环
方法二:while循环
方法三:until循环
循环控制语句:
continue:提前结束本轮循环,而直接进入下一轮循环判断;
while CONDITION ;do
CMD1
…
if CONDITION2;then
continue
fi
CMDn
…
done
示例:求100以内所有偶数之和:
Break:提前跳出循环
While CONDITION1;do
CMD1
…
if CONDITION2;then
break
fi
done
创建死循环:
while true;do
循环体
done
退出方式;某个测试条件满足时,让循环执行break命令;
示例:求100以内所有奇数之和;
sleep命令:
delay for a specified amount of time
sleep number
练习:每隔3秒到系统上获取已经登录的用户的用户信息;其中,如果cladue用户登录系统,则记录于日志中,并退出;
While循环的特殊用法(遍历文件的行)
While read VARIABLE;do
循环体
done < /PATH/FROM/SOMEFILE
一次读取/PATH/FROM/SOMEFILE文件中的每一行,且将基赋值给VARIABLE变量;
示例:找出ID号为偶数的用户,显示其用户名、ID以及默认shell;
for循环的特殊用法:
for ((控制变量初始化;条件判断表达式;控制变量的修正语句));do
循环体
done
控制变量初始化:仅在循环代码开始运行时执行一次;
控制变量的修正语句:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;
示例:求100以内所有正整数之和;
示例;打印九九乘法表;
case语句:
case语句的语法格式:
case $VARAIBLE in
PAT1)
分支1
;;
PAT2)
分支2
;;
…
*)
分支n
;;
esac
case支持的glob风格的通配符:
*:任意长度的任意字符;
?:任意单个字符;
[]:范围内任意单个字符;
a|b:a或b
示例1:显示一个菜单给用户;
cpu) display cpu information
mem) display memoryinformation
disk) display disksinformation
quit) quit
要求:(1) 提示用户给出自己的选择;
(2) 正确的选择则给出相应的信息;否则,则提示重新选择正确的选项;
示例:写一个服务框架脚本:
$lockfile,值/var/lock/subsys/SCRIPT_NAME
1)接受参数start,stop,restart,status四个参数之一;
2)如果参数非此四者,则提示使用帮助后退出;
4)Start,则创建lockfile,并显示启动;stop,则删除lockfile,并显示停止;restart,则先删除此文件再创建文件,而后显示重启完成;status,如果lockfile存在,显示running,否则,显示stoped。
Note:第一行代码basename $0.获取脚本的名字。想对哪个服务管理,将脚本改成对应的名字即可;
函数:function
过程式编程:代码重用
模块化编程
结构化编程
把一段独立功能的代码当作一个整体,并为之一个名字;命名的代码段,此即为函数;
Note:定义函数的代码段不会自动执行,在调用时执行;所谓调用函数在代码中给定函数名即可;
函数名出现的任何位置,在代码执行时,都会被自动替换成函数代码;
语法一:
function f_name {
…函数体…
}
语法二:
f_name() {
…函数体…
}
函数的生命周期:每次被调用时创建,返回时终止;
其状态返回结果为函数体中运行的最后一条命令的状态结果;
自定义状态返回值,需要使用return
return [0-255]
0:成功
1-255:失败
示例:给定一个用户名,取的用户的id号和默认shell;
示例2:上述例子的服务脚本框架(用函数)
函数返回值:
函数的执行结果返回值;
1)使用echo或print命令进行输出;
2)函数体中调用的命令的执行结果;
函数的退出状态码:
1)默认取决于函数体中执行的最后一条命令的退出状态码;
2)自定义:return
函数可以接受参数:
传递参数给函数:
在函数体当中,可以使用$1,$2,…引用传递给函数的参数,还可以函数中使用$*或[email protected]引用所有的参数,$#引用传递的参数的个数;
在调用函数时,在函数名后面以空白符分隔给定参数列表即可,例如,testfunc arg1 arg2 arg3…
示例:添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数;
练习:写一个脚本,使用函数ping一个主机来测试主机的在线状态;主机地址通过参数传递给函数;
主程序:测试192.168.19.129-192.168.19.139范围内主机的在线状态;
练习:打印N*N乘法表;
变量作用域:
局部变量:作用域是函数的生命周期;在函数结束时被自动销毁;
定义局部变量的方法:localVARIABLE=VALUE
本地变量:作用域是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell脚本程序文件;
示例程序:
函数递归:
函数直接或间接调用自身:
示例:求10!