shell脚本编程:
编程基础
程序:指令+数据
编程语言的分类:根据运行方式
编译运行:源代码–>编译器(编译)–>程序文件
解释运行:源代码–>运行时启动解释器,由解释器边解释边运行;
根据其编程过程中功能的实现是调用库还是调用外部的程序文件
shell脚本编程
利用系统上的命令及编程组件进行编程
完整编程;
利用库或编程组件进行编程
编程模式:
面向过程的编程语言
以指令为中心来组织代码,数据是服务于代码的;
顺序执行
选择执行
循环执行
代表:c bash
面向对象的编程语言
以数据为中心来组织代码,围绕数据开组织指令;
类(class):实例化对象,method;
代表:java c++ python
shell脚本编程:过程式编程,解释运行,依赖于外部程序文件运行;
作用:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
1如何写shell脚本
脚本文件第一行,顶格;给出shell类型,解释器路径,用于指明执行当前脚本的解释器程序文件
常见解释器:
#!/bin/bash
#!/bin/python
#!/bin/perl
第二步,写脚本正文
#author:创作者
#Version:版本号
#Description:功能描述
#time:时间
第三步:运行脚本
给予执行权限,在命令行上指定脚本的绝对或相对路径 chmod+x
直接运行解释器,将脚本作为解释器程序的参数运行 ./file
2语法检查
bash -n /path/to/some_script
3脚本调试执行(显示执行过程)
bash -x /path/to/some_script
变量
程序:指令+程序
指令:有程序文件提供
数据:IO设备给出标准输入 ,文件,管道,变量
程序:算法+数据结构
变量:变量名+指向的空间空间
作用:
1,数据存储格式;
2.参与的运算
3.表示的数据范围
数据存储方式(类型):
字符:
数值: 整型,浮点型
数值类型 | 所占字符数 | 取值范围 |
byte | 1 | 0-255 |
short | 2 | 65535 |
int | 4 | 40亿 |
booleam | ||
long | 4 | |
float | 4 | |
double | 8 | |
chart |
变量类型:存储格式,表示数据范围,参与的运算
编程语言:
强类型变量:
定义变量时必须指定类型,参与运算必须符合类型
要求, 调用未声明变量会产生错误
例: C C++ java python
弱类型变量:
无需指定类型,默认均为字符型,;参与运算时会自动进行隐形类型转换,连梁无需事先定义可直接调用
bash 把所有变量统统是做字符类型;
bash不支持浮点类型数据
bash中变量无需事先声明,相当于,把声明和赋值过程同时实现。
声明:类型 变量名
(shell)变量赋值:name=value(值)
变量替换;把变量名出现的位置替换为其所指向的内存空间中数据;
变量引用:${var_name},$var_name
变量名命名方式:
1.变量只能包含数字,字母和下划线;不能以数字开头;
2 不能使用程序关键字,if else
3.见名知意
4,统一命名法:驼峰命名法
bash变量类型:pstree 进程树
本地变量:作用域为当前shell进程,对当前shell外的其他shell进程,包括当前shell的子shell进场June无效
变量赋值:name=value(值)
变量引用:${name},$nameo
"":变量名会替换为其值
'':变量名不会替换为其值
查看变量:set
撤销变量:unset name (释放是个良好的习惯,编写脚本主动释放)
注意:此处非变量引用
echo 变量(命令) 默认显示为一行 echo "变量(命令)" 显示命令原有的输出格式
环境变量:作用域为当前shell进程及子进程
变量赋值:
(1)export name=value(值)
(2)name=value(值)
export name}
(3)declare -x name=value(值)
(4)name=value(值)
declare -x name
变量引用:${name},$name
注意:bash内嵌了许多环境变量(通常为全大写字符),用于定义bash的工作环境
系统自带变量(可直接引用):PWD USER OLDPWD HISTSIZE HISTCONTROL PATH, SHELL,UID,HOME,OLDPWD, HISTFILE, PS1
查看环境变量:export declare -x printenv env
撤销变量:unset name
只读变量:
(1)declare – r name=value
declare – rx name =value 定义常量
(2)readonly name
只读变量无法重新赋值,并且不支持撤销,存活时间为当前shell进程的生命周期,随shell的终止而撤销
局部变量:作用域为当前shell进场中某代码片段(函数)
位置参数变量:
向执行脚本的shell进程传递的参数 $1, $2, …来表示,用于让脚本在脚本代码
$0,:命令 本身
$*: 传递给脚本的所有参数,全部参数合为一个整体
$@,传递给脚本的所有参数,每个参数为独立字符串
注: $@ $* 只有在被双引号包起来的时候有区别
$#:传递给脚本的参数的个数
轮替:
shift [n]: 位置变量轮替,踢掉参数的值,后面的值移动到前一位位置参数
示例:判断给出的文件的行数
linecount="$(wc -l $1| cut -d' ' -f1)"
echo "$1 has $linecount lines."
中调用通过命令行传递给它的参数
特殊变量:shell内置的有特殊功用的变量
$?:执行状态返回值
0:成功
1-255:失败
默认是脚本中执行的最后一条命令的状态返回值
自定义站台返回值:
exit [n]:n为自己指定的状态码
注意:shell进程遇到exit是,会终止,整个脚本执行即为结束
例:id user3 &>/dev/null &&exit 0|useradd user3
算数运算
bash中的算术运算:help let
+, -, *, /, %取模(取余) , **(乘方)
实现算术运算:
(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 …)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
expr $var+0 判断数值是否是整数
expr 运算乘法 乘法符号需要加转义字符 例 expr 2 \* 3
乘法符号有些场景中需要转义, 如*
bash有内建的随机数生成器: $RANDOM( 1-32767)
echo $[$RANDOM%50] : 0-49之间随机数
赋值:
增强型赋值:
+=, -=, *=, /=, %=
let varOPERvalue
例如:let count+=3
自加3后自赋值
自增,自减: 符号在前,先执行运算操作,相反则是
let var+=1
let var++
let var-=1
let var–
逻辑运算:
true, false
1, 0
与:
1 与 1 = 1
1 与 0 = 0
0 与 1 = 0
0 与 0 = 0
或:
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
非:!
! 1 = 0
! 0 = 1
短路运算:
短路与:
第一个为0,结果必定为0;
第一个为1,第二个必须要参与运算;
短路或:
第一个为1,结果必定为1;
第一个为0,第二个必须要参与运算;
异或: ^
异或的两个值,相同为假,不同为真
聚集命令:
有两种聚集命令的方法:
• 复合式: date; who | wc -l
命令会一个接一个地运行
• 子shell: (date; who | wc -l ) >>/tmp/trace
所有的输出都被发送给单个STDOUT和STDERR
退出状态:
进程使用退出状态来报告成功或失败
• 0 代表成功, 1-255代表失败
• $? 变量保存最近的命令退出状态
例如:
$ ping -c1 -W1 hostdown &> /dev/null
$ echo $?
退出状态码:
bash自定义退出状态码
exit [n]:自定义退出状态码;
注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出
状态取决于exit命令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码
取决于脚本中执行的最后一条命令的状态码
条件测试:
bash自定义退出状态码
exit [n]:自定义退出状态码;
注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出
状态取决于exit命令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码
取决于脚本中执行的最后一条命令的状态码
条件性的执行操作:
根据退出状态而定,命令可以有条件地运行
• && 代表条件性的AND THEN
• || 代表条件性的OR ELSE
例如:
$ grep -q no_such_user /etc/passwd \
|| echo 'No such user'
No such user
$ ping -c1 -W2 station1 &> /dev/null \
> && echo "station1 is up" \
> || (echo 'station1 is unreachable'; exit 1)
station1 is up
tset命令:
长格式的例子:
$ test "$A" == "$B" && echo "Strings are equal"
$ test “$A” -eq “$B” \
&& echo "Integers are equal"
简写格式的例子:
$ [ "$A" == "$B" ] && echo "Strings are equal"
$ [ "$A" -eq "$B" ] && echo "Integers are equal
bash的测试类型:
数值测试:
-gt: 是否大于;
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;
字符串测试:
==:是否等于;
>: ascii码是否大于ascii码
<: 是否小于
!=: 是否不等于
=~: 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;
-z "STRING":字符串是否为空,空为真,不空为假
-n "STRING":字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号
文件测试:
存在性测试
-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: fd表示文件描述符是否已经打开且与某终端相关
-N FILE:文件自动上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
双目测试:
FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设
备上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2;
FILE1 -ot FILE2: FILE1是否旧于FILE2;
组合测试条件
双目测试:
FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设
备上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2;
FILE1 -ot FILE2: FILE1是否旧于FILE2;
组合测试条件:
第一种方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如: [ -e FILE ] && [ -r FILE ]
第二种方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必须使用测试命令进行;
# [ -z “$HOSTNAME” -o $HOSTNAME "==\
"localhost.localdomain" ] && hostname www.magedu.com
# [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
使用read命令来接受输入:
使用read来把输入值分配给一个或多个shell变量:
-p 指定要显示的提示
-t TIMEOUT
read 从标准输入中读取值,给每个单词分配一个变量
所有剩余单词都被分配给最后一个变量
read -p “Enter a filename: “ FILE
练习:
1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。
[root@wen-7 shangkelianxi]# cat sh01.sh #!/bin/bash clear echo "显示当前主机信息:" echo "主机名:`hostname`" echo "IPV4地址:` ifconfig eno16777736| grep "inet\>"|tr -s "[[:space:]]" ":"| cut -d: -f3`" echo "操作系统版本:`cat /etc/centos-release | grep -v "^$" `" echo "内核版本: `uname -r`" echo "CPU型号: `cat /proc/cpuinfo | grep "^model name"| cut -d: -f2`" echo "内存大小:`free -h|grep "^Mem" |tr -s " " ':'| cut -d: -f2`" echo "硬盘大小: `fdisk -l| grep ".*/dev/sda\>"`" [root@wen-7 shangkelianxi]# bash sh01.sh 显示当前主机信息: 主机名:wen-7 IPV4地址:172.18.19.219 操作系统版本:CentOS Linux release 7.2.1511 (Core) 内核版本: 3.10.0-327.el7.x86_64 CPU型号: Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz 内存大小:977M 硬盘大小: 磁盘 /dev/sda:21.5 GB, 21474836480 字节,41943040 个扇区
2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中(配合计划任务完成)
备份/etc/到/root/etcYY-MM-DD 并检查文件是否备份成功! backup /root/etc2016-08-12-08-12 ing /root/etc2016-08-12-08-12 is exit,no cp /etc [root@wen-7 shangkelianxi]# cat sh02.sh #!/bin/bash clear echo "备份/etc/到/root/etcYY-MM-DD 并检查文件是否备份成功!" time1=`date +%d` dirname=/root/etc`date +%F-%m-%d` echo "backup $dirname ing" && cp -a /etc/ $dirname [ -f $dirname ] && echo " backup %dirname over "|| echo "$dirname is exit,no cp /etc"
3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值
显示当前硬盘分区中空间利用率最大的值:32% [root@wen-7 shangkelianxi]# cat sh03.sh #!/bin/bash clear num=`df -h| tr -s ' ' ':'| cut -d: -f1,5| grep ':[0-9]'| sort -t: -k2 -n| tail -n1` unmn=` df | grep '/dev/sd' |sed -r 's/^.* ([0-9]+%).*/\1/' |sort -nr|head -1` echo "显示当前硬盘分区中空间利用率最大的值:$unmn"
4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序
显示正连接本主机的每个远程主机的连接数和IPv4地址: 4 172.18.19.1 [root@wen-7 shangkelianxi]# cat sh04.sh #!/bin/bash num=`netstat -nt| tr -s " " ':'|cut -d: -f6| grep [0-9]| uniq -c| sort -n ` echo -e "显示正连接本主机的每个远程主机的连接数和IPv4地址:\n $num"
5、写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和
[root@wen-7 shangkelianxi]# cat sh05.sh #!/bin/bash clear dir=/etc/passwd n=10 m=20 id_10=`cat $dir| head -$n| tail -1|cut -d: -f3` id_20=`cat $dir| head -$m| tail -1|cut -d: -f3` #num=$((${id_10}+${id_20})) num=$[id_10+id_20] echo " $dir文件中的第$n个用户和第$m用户的ID之和:$num" [root@wen-7 shangkelianxi]# bash sh05.sh /etc/passwd文件中的第10个用户和第20用户的ID之和:184
6、写一个脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
[root@wen-7 shangkelianxi]# bash sh06.sh /etc/rc.d/init.d/functions 两个文件的所有空白行之和为70 [root@wen-7 shangkelianxi]# cat sh06.sh #!/bin/bash sum=0 while [ $# -gt 0 ] do num=`cat $1| grep "^[[:space:]]*$" | wc -l` sum=$(($sum+$num)) shift done echo "两个文件的所有空白行之和为$sum " unset sum
7、写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
[root@wen-7 shangkelianxi]# cat sh07.sh #!/bin/bash dir=0 file=0 name="/etc/ /var /usr" for line in $name do dirie=`ls -p $line| grep "/$"| wc -l` dir=$(($dir+$dirie)) fileie=`ls -p $line| grep -v "/$"| wc -l` file=$(($file+$fileie)) done echo "$name 一共为目录为$dir个,文件为$file个" [root@wen-7 shangkelianxi]# bash sh07.sh /etc/ /var /usr 一共为目录为179个,文件为175个
8、写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
[root@wen-7 shangkelianxi]# bash sh08.sh 至少应该给一个参数: [root@wen-7 shangkelianxi]# bash sh08.sh /etc/passwd the file /etc/passwd has space list is:0 [root@wen-7 shangkelianxi]# bash sh08.sh /etc/grub2.cfg the file /etc/grub2.cfg has space list is:17 [root@wen-7 shangkelianxi]# cat sh08.sh #!/bin/bash clear [ $# -lt 1 ] && echo " 至少应该给一个参数:" || echo "the file $1 has space list is:`cat $1| grep "^$"| wc -l`"
9、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
[root@wen-7 shangkelianxi]# cat sh09.sh #!/bin/bash ping -c1 -w1 $1 &>/dev/null [ $? -eq 0 ] && echo "this ip is ok login" || echo "ERROR: this ip is no login" [root@wen-7 shangkelianxi]# bash sh09.sh 172.18.19.219 this ip is ok login [root@wen-7 shangkelianxi]# bash sh09.sh 172.18.19.210 ERROR: this ip is no login
10、chmod -rw /tmp/file1,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1文件是否不可读且不可写
[wen@wen-7 ~]$ bash sh10.sh the file is no read and no write for one user [wen@wen-7 ~]$ ll /tmp/file1 ---------- 1 root root 0 8月 12 09:53 /tmp/file1 [wen@wen-7 ~]$ bash sh10.sh the file is read and write for one user [wen@wen-7 ~]$ cat sh10.sh #!/bin/bash FileName=/tmp/file1 [ ! -e $FileName ] && echo "file $FileName is no exits" && exit 2 #chmod -rw $FileName &>/dev/null if [ -r $FileName -a -w $FileName ];then echo "the file is read and write for one user" else echo "the file is no read and no write for one user" fi
11、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统。
#!/bin/bash file=/etc/nologin while true do clear echo -e "\033[31m" cat << EOF ######################## (y|Y):DOWN user login # (n|N):UP user logion # (q): exit shell # ######################## EOF echo -e "\033[0m" read -p " 是否对普通用户登录进行操作(参考列表输入):" input case $input in y|Y) [ -f /etc/nologin ] && echo "user disable login already" || touch /etc/nologin; echo "user disable no login " exit 2 ;; n|N) [ -f /etc/nologin ] && rm -f /etc/nologin;echo "user enable login" || echo "user disable login already " exit 3 ;; q) exit ;; esac done
12、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,先判断是否合格IP,否,提示IP格式不合法并退出,是,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
[root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :172.18.19.219 this ip is ok login [root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :172.18.19.210 ERROR: this ip is no login [root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :123.12312.3 the ipv4 dir is no ok [root@wen-7 shangkelianxi]# cat ping2.sh #!/bin/bash read -p "enter a ipv4 dir :" input echo $input|egrep "\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3} [0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"&>/dev/null ##匹配输入的ipv4地址是否合格 if [ $? -gt 0 ] ;then echo "the ipv4 dir is no ok" exit 2 else ping -c1 -w1 $input &>/dev/null [ $? -eq 0 ] && echo "this ip is ok login" || echo "ERROR: this ip is no login" fi
13、计算1+2+3+…+100的值
[root@wen-7 shangkelianxi]# bash numsum.sh 1..100的和为5050 [root@wen-7 shangkelianxi]# cat numsum.sh #!/bin/bash sum=0 num=`seq 1 100` for i in $num do sum=$[$sum+$i] done echo "1..100的和为$sum"
14、计算从脚本第一参数A开始,到第二个参数B的所有数字的总和,判断B是否大于A,否提示错误并退出,是则计算之
[root@wen-7 shangkelianxi]# bash wei.sh 10 5 10,5 5小于10,不符合规定 请重新输出参数 [root@wen-7 shangkelianxi]# bash wei.sh 5 10 5,10 参数1与参数2之和为45 [root@wen-7 shangkelianxi]# cat wei.sh #!/bin/bash sum=0 echo "$1,$2" [ $# -eq 0 ] && echo "enter at least one parameter :" && exit 2 if [ $1 -lt $2 ];then for i in `seq $1 $2` do sum=$[$sum+$i] done echo "参数1与参数2之和为$sum" else echo " $2小于$1,不符合规定" echo " 请重新输出参数" exit 4 fi
15.当某磁盘的使用率大于80的时候,则自动报警
[root@wen-7 shangkelianxi]# bash checkdisk.sh disk /dev/sda1 is wall [root@wen-7 shangkelianxi]# cat checkdisk.sh #!/bin/bash num=`df -h| tr -s " " | cut -d" " -f1,5| sort -t' ' -k2 | grep " [0-9]\+"|tail -n1|cut -d" " -f1` num1=`df| grep "/dev/sd"|sed -r 's@.* ([0-9]+)%.*@\1@'| sort| tail -1` [ "$num1" -ge "80" ] && echo "ERROR: wall disk$num will be full!!!" || echo " disk $num is wall"
原创文章,作者:wencx,如若转载,请注明出处:http://www.178linux.com/33812
评论列表(1条)
总结的很好,很详细,题目尽量不要带练习,作业什么的,只要给出自己写的内容就行了。