1.Shell编程简介
Shell是操作系统的最外层,Shell可以合并编程语言以控制进程和文件,以及启动和控制其它程序。Shell 通过提示您输入,向内核解释该输入,然后处理来自内核的任何结果输出。
简单来说Shell就是一个用户跟操作系统之间的一个命令解释器。
Linux Shell种类非常多,常见的SHELL如下:
Bourne Shell(/usr/bin/sh或/bin/sh) shell是有bourne shell发展起来的 Bourne Again Shell(/bin/bash) C Shell(/usr/bin/csh) K Shell(/usr/bin/ksh) Shell for Root(/sbin/sh)
查看系统中的shell类型
[root@node2 ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
shell脚本在运维工作中的地位
shell脚本很擅长处理纯文本类型的数据,而在linux中几乎所有的配置文件,日志文件(nfs,rsync,httpd,nginx,lvs)等都是纯文本类型的文件
查看shell解释器类型
echo $SHELL
shell脚本后台执行
sh test.sh & 放到后台执行
shell脚本命令规则
Shell脚本名称命名一般为英文、大写、小写; 不能使用特殊符号、空格来命名; Shell脚本后缀以.sh结尾; 不建议Shell命名为纯数字,一般以脚本功能命名。 Shell脚本内容首行需以#!/bin/bash开头; Shell脚本中变量名称尽量使用大写字母,字母间不能使用“-”,可以使用“_”; Shell脚本变量名称不能以数字、特殊符号开头。
shell脚本内容详解
#!/bin/bash 固定格式,定义该脚本所使用的Shell解释器类型; #This is my First shell #号表示注释,没有任何的意义,SHELL不会解析; #By author 2017 表示脚本创建人,#号表示注解; echo “Hello World !” Shell脚本主命令,执行该脚本呈现的内容。
注意:shell脚本必须要有执行权限
2.shell编程变量
Shell编程是非类型的解释型语言,不像C++、JAVA语言编程时需要事先声明变量,Shell给一个变量赋值,实际上就是定义了变量,在Linux支持的所有shell中,都可以用赋值符号(=)为变量赋值,Shell变量为弱类型,定义变量不需要声明类型,但在使用时需要明确变量的类型,可以使用Declare指定类型,Declare常见参数有:
+/- "-"可用来指定变量的属性,"+"为取消变量所设的属性; -f 仅显示函数; r 将变量设置为只读; x 指定的变量会成为环境变量,可供shell以外的程序来使用; i 指定类型为数值,字符串或运算式
Shell编程中变量分为三种,分别是系统变量、环境变量和用户变量,其中系统变量在对参数判断和命令返回值判断时使用,而环境变量则主要是在程序运行时需要设置,用户变量又称为局部变量,多使用在Shell脚本内部或者临时局部使用。
系统变量:
$0 当前脚本的名称;
$n 当前脚本的第n个参数,n=1,2,…9;
$* 当前脚本的所有参数(不包括程序本身);
$# 当前脚本的参数个数(不包括程序本身);
$? 命令或程序执行完后的状态,返回0表示执行成功;
$$ 程序本身的PID号。
环境变量:
PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名
用户变量:
A=啦啦啦啦啦 自定义变量A;
N_SOFT=nginx-1.12.0.tar.gz 自定义变量N_SOFT;
BACK_DIR=/data/backup/ 自定义变量BACK_DIR;
IP1=192.168.1.11 自定义变量IP1;
IP2=192.168.1.12 自定义变量IP2。
other:
1.a=123 使用$a来引用变量,取消定义的变量:unset a
2.使用env命令来查看当前的变量
3.变量直接链接
a=123 b=456
echo $a 输出123
echo $b 输出456
echo $ab 输出空
echo $a\b 输出123b
echo echo $a$b 或者echo${a}${b} 输出123456
4.系统变量不能自定义,环境变量可以自定义
export abc=www.baidu.com
echo “export abc=www.baidu.com” >>/etc/profile 加入到全局变量文件
source /etc/profile 加载文件
Shell变量名在定义时,首个字符必须为字母(a-z,A-Z),不能以数字开头,中间不能有空格,可以使用下划线(_),不能使用(-),也不能使用标点符号等。
拓展:清空日志及文件内容的三种方法
echo >test.log >test.log cat /sev/null >test.log
3.常见的判断和shell里面的括号
常见的逻辑判断
-f 判断文件是否存在 eg: if [ -f filename ]; -d 判断目录是否存在 eg: if [ -d dir ]; -eq 等于,应用于整型比较 equal; -ne 不等于,应用于整型比较 not equal; -lt 小于,应用于整型比较 letter; -gt 大于,应用于整型比较 greater; -le 小于或等于,应用于整型比较; -ge 大于或等于,应用于整型比较; -a 双方都成立(and) 逻辑表达式 –a 逻辑表达式; -o 单方成立(or) 逻辑表达式 –o 逻辑表达式; -z 空字符串; || 单方成立; && 双方都成立表达式。
注意:在[]和[[]]中使用,如果就是要在[]使用‘<’或者‘>’等,就需要转移,因为shell也是用‘<’和‘>’进行重定向
[-eq -ne -lt -gt -le -ge ]:在使用这种-eq等符号时,一定保证两端都是整数
[[ == != < > <= >= ]]
常见的文件测试操作符 -f 文件,英文file,文件存在并且为普通文件则真,表达式成立 -d 文件,英文directory,文件存在并且为目录文件则真,表达式成立 -s 文件,英文size,文件存在并且文件大小不为0则真,表达式成立 -e 文件,英文exist,文件存在则真,只要有文件就行,区别-f,表达式成立 [ -e test2 ]&& echo 1||echo 0:可以是文件,也可以是目录 -rwx 文件,英文read,write,executable,文件存在并且可读可写可之心则真,表达式成立 -L 文件,英文link,文件存在并且为连接文件则真,表达式成立 f1 -nt f2,英文,newer than,文件f1比f2新则真,表达式成立,根据修改时间计算 f1 -ot f2,英文,older than,文件f1比f2旧则真,表达式成立,根据修改时间计算
注意:
[ -f /etc/passwd ]&&{ echo 1;echo 2;echo 3;} #判断文件,之后执行大括号里面的内容,大括号里面可以是命令
常见的字符串表达式
-z “字符串” 若长度为0,则真,-z可以理解为是否为空zero
-n “字符串” 若长度不为0,则真,-n可以理解为no zero
“串1” = “串2” 若串1等于串2则真,可使用‘==’代替‘=’
“串1” != “串2” 若串1不等于串2则真,不能使用‘!==’代替‘!=’
注意:
1.以上中的字符串测试操作符号务必要用""引起来
2.比较符号两端有空格
3.-z前面加上!代表取反,相当于-n 例子:[ ! -z "" ]&&echo 1||echo 0
shell中的括号对比
() 用于多个命令组、命令替换、初始化数组;
(()) 整数扩展、运算符、重定义变量值,算术运算比较、gt、lt;
[]bash 内部命令,[与test是等同的,正则字符范围、引用数组元素编号,不支持+-*/数学运算符,逻辑测试使用-a(and)、-o(or)、gt、lt。
[[ ]] bash程序语言的关键字,不是一个命令,[[ ]]结构比[ ]结构更加通用,不支持+-*/数学运算符,逻辑测试使用&&、|| 、gt、lt等。
{} 主要用于命令集合或者范围,例如mkdir -p /data/201{7,8}/或者[ -f /etc/passwd ]&&{ echo 1;echo 2;echo 3;}
这样记住会比较好 [ ]写的表较少,就可以使用-a -o ,[[ ]]比较多就可以使用&&和||
多个[]之间以及多个[[]]之间或者人以混合中间逻辑操作符都是&&或者||
拓展
test 命令 相当于shell里面的中括号[ man test可以看test命令里面的参数的使用以及含义,也适用于其他命令 $UID为系统变量 查看是否使用roto账户 cat>/tmp/data.txt <<EOF lalalall EOF 相当于cat “lalalala” >/tmp/data.txt已覆盖的形式写入到data.txt里面 \033[32m ===== \033[0m ! 不等于的意思 date +%Y%m%d%H%M%S 获取时间 $UID为系统变量 判断是否为root用户运行 s%/123123/456456/g 将全文的123123改成456456 #和\ 转移字符 sh -x test.sh 查看shell脚本执行的详细信息 date +%F 2015-10-16 cut -d ":" -f 1 切割文件 -d:以什么分割 -f:取多少列
通过键盘读入的方式比较两个数的大小
#!/bin/bash read -p "please input mumber:" a b [ $a -ge $b ]&&echo "$a>$b"||echo "$a<$b"
把lalalall写入文件
cat>/tmp/data.txt<<EOF lalalall EOF 相当于cat “lalalala” >/tmp/data.txt已覆盖的形式写入到data.txt里面
编写二级菜单
#!/bin/bash
#2018年11月28日14:52:19 #by p0st menu(){ cat <<EOF 1.{install lnmp} 2.{install net-tools} 3.{exit} EOF } menu read -p "please input num": num [ $num -eq 1 ]&&{ echo "install lnmp" #[ -x /serverscripts/lnmp.sh ] ||exit 2 #判断脚本是否有执行权限 #/bin/bash /serverscripts/lnmp.sh exit 0 } [ $num -eq 2 ]&&{ echo "install net-tools" #[ -x /serverscripts/net-tools.sh ] ||exit 2 #判断脚本是否有执行权限 #/bin/bash /serverscripts/net-tools.sh exit 0 } [ $num -eq 3 ]&&{ echo "exit " exit 0 }
4.逻辑判断
4.1if条件语句
If条件判断语句,通常以if开头,fi结尾。也可加入else或者elif进行多条件的判断,if表达式如下:
if语法:
if[ 条件 ];then echo 1 fi
前文的[ -f "$file" ]&&echo 1 就相当于
if [ -f $file ];then
echo 1
fi
前文的[ -f "$file" ]&&echo 1||echo 0 就相当于
if [ -f $file ];then
echo 1
else
echo 0
fi
多分支if
if [ -f $file ];then
echo 1
elif [ -f $file1 ];then
echo 0
else
echo -1
fi
拓展
判断两个数大小
#!/bin/bash
NUM=100
if (( $NUM > 4 )) ;then
echo “The Num $NUM more than 4.”
else
echo “The Num $NUM less than 4.”
fi通过键盘读入的方式比较两个数的大小
#!/bin/bash read -p "please input mumber:" a b if[ $a -ge $b ];then
echo "$a>$b"
else
echo "$a<$b"#判断内存使用大小,如果小于100m,就发送邮件,并且添加到定时任务里面,就每三分钟执行一次监控脚本,
#!/bin/bash #2018年11月28日16:02:49 #by p0st mem=`free -m|grep "^Mem"|awk '{print $7}'` if [ $mem -gt 100 ];then echo "Mem:"$memi"M" echo "Men less than 100m" else echo "正在发送邮件" "set from=yourname@163.com smtp=smtp.163.com\nset smtp-auth-user=yourname@163.com\n smtp-auth-password=yourpassword\n smtp-auth=login\n">>/etc/mail.rc mail -s "men free" admin@qq.com echo “已经添加定时任务” echo “3 * * * * /bin/bash /serverscripts/men.sh ” >>/var/spool/cron/root fi
#将目录中所有文件的MD5的值写入文件,进行目录监控
find /serverscripts/ -type f |xargs md5sum >/tmp/md5list #查找文件算出MD5存放到/tmp/md5list
md5sum -c md5list #进行MD5比较
[root@node1 serverscripts]# md5sum -c md5list
/serverscripts/1.sh: FAILED
/serverscripts/2.sh: OK
/serverscripts/menu.sh: OK
serverscripts/md5list: FAILED
md5sum: WARNING: 2 computed checksums did NOT match
4.2 case条件语句
case实际上就是规范的多分支if语句
case "kobe" in
值 1) 指令一
;;
值 2) 指令二
;;
easc
case语句判断输入数据
#!/bin/bash read -p "Please input number:" num case "$num" in 1) echo "111" ;; 2) echo "222" ;; *) echo " lalalal" ;; esac
打印闪烁的花
#/bin/bash cat > 1.file << EOF / \./ \/\_ I Hand You __{^\_ _}_ ) }/^\ A Rose / /\_/^\._}_/ // / ( (__{(@)}\__}.//_/__A___A______A_______A______A____ \__/{/(_)\_} )\\ \\---v----V-----V--Y----v---Y----- ( (__)_)_/ )\ \> \__/ \__/\/\/ \__,--' EOF file=`cat 1.file` echo -e "\e[35;40;1;5m $file \e[0m "
5.shell函数
来说函数之前,我们先了解下别名
[root@node2 ~]# alias lalala='id'
[root@node2 ~]# lalala
uid=0(root) gid=0(root) groups=0(root)
[root@node2 ~]#
提示:输出lalala指令就相当于执行id命令,函数也是具有和别名类似的功能,对于linux系统的2000个命令都可以说是shell的函数
函数
函数作用: 1.重复调用,解耦,让程序代码结构更清晰 2.减少代码量 3.实现程序功能的模块化
函数语法:
function 函数名(){
指令。。。。
return m #shll的返回值是exit输出返回,函数里面你是return输出返回值
}
函数执行:
1.直接执行函数名即可,不加小括号
2.带参数的函数执行方法,执行: 函数名 参数一 参数二
编写第一个shell脚本函数
#!/bin/bash
#2018年12月4日14:33:19
#p0st
function aa(){
echo "this is myfirst func"
}
aa #这是在调用函数
函数调用方法
[root@node1 serverscripts]# /bin/bash fun01.sh this is myfirst func [root@node1 serverscripts]#
还有一种调用方法
在/etc/init.d/functions 里面写函数,在其他函数里面调用
vim /etc/init.d/functions,在最后面添加
bb(){
echo "bb test lalala"
}
在aa函数里面引用bb函数
#!/bin/bash
#2018年12月4日14:33:19
#p0st
. /etc/init.d/functions 或者使用source /etc/init.d/functions来引用
function aa(){
echo "this is myfirst func"
}
aa
bb
编写第二个函数脚本(通过curl来判断网址是否存在)
#!/bin/bash [ -f /etc/init.d/functions ]&& . /etc/init.d/functions #判断系统函数是否存在 RETVAL=0 usage(){ echo "Usage:$0 url" exit 1 } check(){ wget -T 10 --spider -t 2 $1 &>/dev/null RETVAL=$? if [ $RETVAL -eq 0 ];then action "$1 url" /bin/true else action "$1 url" /bin/false fi return $RETVAL } main(){ if [ $# -ne 1 ];then usage fi check $1 return $RETVAL } main $*
调用方式:sh ./check.sh www.baidu.com
编写第三个函数脚本(输入参数一是颜色,参数二是文本,将文本打印成参数一的颜色)
#!/bin/bash #2018年12月4日15:51:04 red='\E[1;31m' green='\E[1;32m' yellow='\E[1;33m' blue='\E[1;34m' pink='\E[1;35m' res='\E[0m' color(){ if [ "$1" = "red" ];then echo -e "$red $2 $res" exit 1 elif [ "$1" = "green" ];then echo -e "$green $2 $res" exit 1 elif [ "$1" = "yellow" ];then echo -e "$yellow $2 $res" exit 1 elif [ "$1" = "pink" ];then echo -e "$pink $2 $res" exit 1 elif [ "$1" = "blue" ];then echo -e "$blue $2 $res" exit 1 fi echo "input error" exit 1 } main(){ if [ $# -eq 2 ];then color $1 $2 else echo "usage: $0 color text " fi } main $*
调用方式:sh ./color.sh red 123
啦啦啦