shell脚本编程(1)
脚本的基本格式:
程序:指令+数据
程序编程风格分为两种:
过程式:以指令为中心,数据服务于指令
对象式:以数据为中心,指令服务于数据
过程式编程有以下几个特点:
顺序执行
循环执行
选择执行
shell编程:
过程式、解释执行
编程语言的基本结构
数据存储:变量、组数
表达式:a+b
语句: if
shell程序:是一个过程式的解释器,提供了编程能力,解释执行
程序的执行过程:先把源码程序翻译成机器语言(生成可执行的文件),然后解释执行。
对于过程式编程而言,把一行源码程序翻译成机器语言,然后执行,在翻译下一行的源码程序为机器语言,然后再次执行
对于计算机,只能识别的是二进制文件
编程语言:
低级:
汇编语言
高级:
编译过程:高级语言>编译器>目标代码 如:java ,C
解释过程:高级语言>解释器>机器代码 如: shell,perl,python
shell 脚本其实就是以一系列命令组合起来的文本文件,这些命令组合起来完成一个或者一项功能。
也可以这样理解 shell脚本是包含好一些命令或声明,并符合一定格式的文本文件
格式要求:shell程序开头的环境指定,我们称之为shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
各种命令组合在一起,形成一个脚本
shell脚本的用途有:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
创建shell脚本:
使用编辑器来创建文本文件
第一行必须包括shell声明序列:#! #!/bin/bash
添加注释信息 以#开头
运行脚本:
给予执行权限,通过具体的文件路径制定文件执行
直接运行解释器,将脚本作为解释器程序的参数运行
脚本调式:
bash -n /path/to/some_script 检查脚本中是否语法错误
bash -x /path/to/some_script 调试执行
shell脚本格式示例
#!/bin/bash/ 开头格式
# 注释信息
# Author: root
# date: 20160812-08:12:08
# Vervion: 0.0.1
# Description:
# Synopsis:
echo "信息内容"
关于变量:
什么是变量:命名的内存空间
数据存储方式
变量作用类型:
作用:
数据存储格式
参与运算
表示的数据范围
类型 :
字符
数值: 整型,浮点型
变量类型分为两类:
强类型:定义变量是必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误
弱类型:无需指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须是想定义可直接调用
变量命名法则:
不能使用程序中的保留字:例如if,for等
只能使用数字、字母及下划线,且不能以数字开头
要做到看到变量名称就知道是什么意思;见名知意
统一命名法则:驼峰命名法
大驼峰:两个单词开头字母为大写
小驼峰:两个单词,第一个开头为小写,第二个开头为大写
bash中变量的种类:
根据变量的生效范围等标准可分为:
本地变量:生效范围为当前shell进程;对当前shell之外的其他shell进程包括当前shell的子shell进程均无效;简单来说,本地变量,只能对本地使用
环境变量:生肖范围为当前shell进程以及子进程。
局部变量:生效范围为当前shelll进程中某代码片段(通常指的是函数)
位置变量:$1,$2,$3,….表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:
$? 上个命令是否执行成功
$0 表示命令本身
$# 传递给脚本参数的个数
$* 传递给脚本的所有参数
$@ 引用传递给脚本的所有参数
pstree 查看树形结构的进程
本地变量:
变量赋值: name='value' (值) 值可以引用
1 可以是直接字符串 例如 name="root"
2 变量引用 例如 name="$username"
3 命令引用 例如 name=`命令`,name=$(命令)
变量引用:$name,${name}
"" 弱引用,其中的变量引用会被替换成变量值
'' 强引用, 其中的便碧昂引用不会被替换变量值,而且保持原字符串
显示已经定义的所有变量:set
销毁变量:unset namme
练习
1编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPV4地址操作系统版本,内核本本,CPU型号,内存大小,硬盘大小
~]# vim systeminfo.sh
#!/bin/bash
#
ip=`ifconfig | grep 'inet\>' | grep -v '127.0.0.1' | tr -s ' ' | cut -d' ' -f3`
cpu=`lscpu | grep -i "model name:"`
neicun=`free -h |sed -n '2p' |tr -s ' ' | cut -d' ' -f2`
cipan=`fdisk -l | sed -n '2p' | sed -r 's/.*[[:space:]]([0-]9.*M).*/\1/g'`
echo 'hostname:'`hostname`
echo 'hostip:'$ip
echo 'OS version:'`cat /etc/redhat-release`
echo 'neihe:'`uname -r`
echo 'cpu:'$cpu
echo 'neicun:'$neicun
echo 'cipan:'$cipan
保存退出,chmod +x systeminfo.sh 加上执行权限,可直接运行
2编写脚本/root/bin/backup.sh,可实现将/etc/目录备份到/root/etcYYYY-mm-dd中
~]# vim backup.sh
#!/bin/bash
backdir="/root/etc$(date +%F)"
cp -a /etc/. $backdir && echo "comon $backdir stop."
保存退出,chmod +x backup.sh 加上执行权限可直接运行
3 编写脚本/root/bin/disk.sh,显示当前硬盘分区 中空间利用最大的值
#!/bin/bash
#
cipanname=`df |grep '/dev/sd' | tr -s ' '|sort -nr -t' ' -k5|cut -d' ' -f1`
shiyonglv=`df |grep '/dev/sd' | tr -s ' '|sort -nr -t' ' -k5|cut -d' ' -f5`
echo $cipanname
echo $shiyonglv
保存退出,chmod +x disk.sh 加上执行权限可直接运行
4 编写脚本/root/bin/links.sh,显示正在连接本主机的每个远程主机的IPV4地址和连接数,并按连接输从大到小排序
#!/bin/bash
#
echo -e "lianjie: \n\tlianjieshu\tip"
netstat -nt |tr -s ' '|cut -d' ' -f5| tr -cs '0-9.' '\n'|egrep '([0-9]+.){3}[0-9]+'|sort|uniq -c|sort -nr|tr -s ' ' '\t'
环境变量;
变量声明、赋值
export name=值 输出 名称 值
declare -x name=值 声明 选项 名称 值
变量引用: $name,${name}
显示所有的环境变量:
export
env
printenv
销毁 : unset name
bash中有许多内建的环境变量:PATH,SHELL,USRE,UID,HISTSIZE,HOME,PWD,OLDPWD,HISTFILE,PS1
只读变量:只能读,但不能修改和删除
readonly name 只读
declare -r name 声明
位置变量:在脚本代码中调用通过命令传递给脚本的参数
$1,$2,$3… 对应调用第1.第2第3等参数
$0 表示命令本身
$* 传递给脚本的所有参数,全部参数何为一个字符串
$@ 引用传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本参数的个数,
$@ $* 只有在被双引号包起来时候才会有差异
bash中的算数运算:help let
+,-,*,/,% 取模式(取值)**(乘方)
实现算数运算:
1 let var=算数表达式
2 var =$[算数表达式] ]# number=$[2**3] ~]# echo $number
3 var =$((算数表达式)) ~]# number=$((2**3)) ~]# echo $number
4 var =$(expr表达式 arg1 arg2 arg3…) 如A=$(expr $B \* $C)
5 declare -i var = 数值
6 echo '算数表达式' | bc
注意:*乘法符号有些场景中需要转义
bash有内建的随机数生成器:$RANDOM(1-32767)
echo $[$RANDOM%50] 表示0-49之间的随机数
echo $[$RANDOM%50+2] 表示1-50之间的随机数
增强型赋值:
+=,-=,*=,/=,%=
使用方法:let var+=5 var值就是5
自增,自减
let var+=5 var=5
let var++ 在原有的数值上面加上1 比如原先设定的是5执行一次let var++就相当于加上数值1
let var-=1 在原有的数值上面减去1个数值
let var– 在原有的数值上面减去1个数值
练习
5 写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20个用户之和
~]# vim sumdi.sh
#!/bin/bash
#
uid1=`sed -n '10p' /etc/passwd | cut -d: -f3`
uid2=`sed -n '20p' /etc/passwd | cut -d: -f3`
let sumid=$uid1+$uid2
echo -e "The 10 user ID is $uid1 ;\nthe 20 user ID is $uid2 ;\n\tthe sum of two users ID is $sumid ."
保存退出 chmod +x sumid.sh 加上执行权限
6写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
~]# vim sumfile.sh
#!/bin/bash
#
file1=`ls -A /etc | wc -l`
file2=`ls -A /var | wc -l`
file3=`ls -A /usr | wc -l`
let sumfile=$file1+$file2+$file3
echo "$sumfile"
逻辑运算
在shell编程当中支持一些逻辑运算: true1 真为1 false0 假为0
与运算:
1与1=1 1&&1=1 1和任何数相与 是原值 1和1相与为原来的值1
1与0=0 1&&0=0 0和任何数相与 是0 1和0相与为原来的值0
0与1=0 0&&1=0 0和1相与 等0
0与0=0 0&&0=0
或运算:
1或1=1 1||1=1 只要有一个是真结果就为真,
1或0=1 1||0=1 只要两个都是假结果就为假,
0或1=1 0||1=1
0或0=0 0||0=0
非运算:
!1=0 非真 则为假
!0=1 非假 则为真
短路运算:
短路与:
第一个为0, 结果必定为0 命令1与命令2
第一个为1,第二个必须要参与运算 假0 假0 如果命令1成功将执行2
如果命令1失败,将不执行命令2
短路或:
第一个为1,结果必定为1 命令1命令2 如果命令1执行成功将不执行命令2
第一个为0,第二个必须要参与运算 真1 真1 如果命令1执行不能功执行命令2
异或:^
异或的两个值,相同为假,不同为真 ‘异性相吸 ,同性为假’ 两个值相同为假,不相同则为真
两种聚集命令的方法:
复合式:date; who| wc -l
命令会一个接一个地运行 顺序执行,从左往右生效
子shell:(date;who | wc -l)>> /tmp/tarce
可以执行单个体命令
(date; who)| wc -l可以先执行括号里面的命令
退出状态进程使用退出状态来报告成功或失败
0 表示成功 ,1-255 代表失败
$? 变量保存最近的命令退出状态
例如 echo $? 可以查看上一条命令是否成功或失败
自定义退出状态码: exit
注意:
1 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
2 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
条件测试:
判断某需求是否满足,需要有测试机制来实现;
专用的测试表达式需要有测试命令辅助完成测试过程;
若真,返回的是0
若假,返回的是1
测试命令:
test 表达式 $w = $r
test [表达式] ] [ $w = $r ]
test [[表达式]] ] [[ $w = $r ]]
注意:表达式 前后必须有空白字符
条件性的执行操作符:
根据退出状态而定,命令可以有条件地运行
命令1 && 命令2 短路与, 命令1成功,将执行命令2 ,如果命令1失败,将不执行命令2
命令1 || 命令2 短路或, 命令1成功,将不执行命令2 ,如果命令1失败,将执行命令2
bash 的测试类型
数值测试:
-gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于
字符串测试:
== 是否等于
> 是否大于
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的表达式所匹配
注意;此表达式一般用于[[ ]]
-z 字符串 字符串是否为空,空为真、不空为假
-n 字符串 字符串是否不空, 不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号
文件测试 :
存在性测试:
-a file 同-e
-e file 文件存在性测试,存在为真,否者为假;
存在性和类别测试:
-b file 是否存在且为块设备文件
-c file 是否存在且为字符设备文件
-d file 是否存在且为目录文件
-f file 是否存在且为普通文件
-h file 或者 -L file 存在且为符号链接文件
-p file 是否存在且为命名管道文件
-S file 是否存在且为套接字文件
文件权限测试:
-r file 是否存在并且可读
-w file 是否存在并且可写
-x file 是否存在并且可执行
文件特殊权限测试:
-g file 是否存在且拥有sgid 的权限
-u file 是否存在切拥有suid 的权限
-k file 是否存在且拥有sticky的权限
文件大小测试:
-s file 是否存在且非空
文件是否打开:
-t fd 文件描述符是否已经打开并且与某终端相关
-N file 文件上一次杜宇之后是否被修改过
-O file 当前有效用户是否为文件属主
-G file 当前有效用户是否为文件属组
双目测试::
file1 -ef file2 文件1和文件2 是否指定向同一个设备上的相同inode 是否为同一个文件
file1 -nt file2 文件1是否新于文件2
file1 -ot file2 文件1是否旧与文件2
组合测试条件:
第一种方式:
命令1 && 命令2 并且
命令1 || 命令2 或者
!命令 非
例如 [ -e file ] && [ -r file ]
第二种方式:
表达式1 -a 表达式2 并且
表达式1 -o 表达式2 或者
!表达式 非
练习
编写脚本/root/bin/nologin.sh和login.sh,实现禁止和允许普通用户登录系统。
#!/bin/bash
#
[ -f /etc/nologin ] && echo "user disable login already" || (touch /etc/nologin; echo user disable login )
禁止普通用户登录
#!/bin/bash
#
[ -f /etc/nologin ] && (rm -f /etc/nologin;echo user enable login) || echo user disable login already
允许普通用户登录
计算1+2+3+…+100的值
#!/bin/bash
#
shuzi=`echo {1..100}|tr ' ' '+'| bc`
echo $shuzi
原创文章,作者:小马哥,如若转载,请注明出处:http://www.178linux.com/35714
评论列表(1条)
总结的很好,很细致,结构清晰,注意理论与实践相结合。