shell编程从入门到高级教程
1.1 shell能做什么
1. 自动化批量系统初始化程序 (update,软件安装,时区设置,安全策略...) 2. 自动化批量软件部署程序 (LAMP,LNMP,Tomcat,LVS,Nginx) 3. 应用管理程序 (KVM,集群管理扩容,MySQL,DELLR720批量RAID) 4. 日志分析处理程序(PV, UV, 200, !200, top 100, grep/awk) 5. 自动备份恢复程序(MySQL完全备份/增量 Crond) 6. 自动化管理程序(批量远程修改密码、软件升级、配置更新) 7. 采集和监控自动化信息(收集系统/应用状态信息)CPU,Mem,Disk,Net,TCP Status,Apache,MySQL) 8. 配合Zabbix信息收集(收集系统/应用状态信息)CPU,Mem,Disk,Net,TCP Status,Apache,MySQL) 9. 自动扩容(增加云主机)——>业务上线) zabbix监控CPU 80% |-50% Python API AWS/EC(增加/删除云主机) Shell Script(业务上线) 10. 俄罗斯方块,打印三角形,打印圣诞树,打印五角星,运行小火车,坦克战争,排序算法,等等 11. Shell能做什么(一切都取决于业务需求)
1.2 shell编程初识
Shell 是命令解释器 Shell 它也是一种程序设计语言,具有变量、关键字、各种控制语句、语法结构和使用shell编写功能强、代码短的程序设计语言**
/bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh /bin/csh
默认shell: bash
注意:各种脚本都是/bin/sh表示使用默认bash
查看目前使用的内容shell: #echo $SEHLL
shell 的更改: #chsh #vim /etc/passwd
如果您需要上述任何应用程序,请考虑其他更强大的脚本语言――Perl,Tcl,Python,Ruby,或者可能是其他更先进的编译语言,如C,C++或者是Java
[root@master1 ~]# cat jiaoben.sh #!/usr/bash liu () {
cat <<-EOF 1.关闭防火墙,一键三连,修改selinux 2.检查系统状态[磁盘的大小和利用率 内存大小和利用率 cpu负载 运行时间 版本号] 3.一键配置yum一键三联,关闭防火墙, 4.修改主机名称,配置静态IP 5.yum安装mysql-5.7 6.安装yum安装 nginx 7.安装jdk8.tomcat8版本 EOF } one (){
systemctl stop firewalld iptables -X && iptables -F && iptables -Z systemctl disable firewalld && systemctl status firewalld sed -ri s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config && getenforce } two () {
cat <<-EOF 1.磁盘的大小和利用率 2.内存大小和利用率 3.cpu负载 4.运行时间 5.版本号 } EOF printf "\e[1;31m 请选择您想要使用的功能(1/2/3/4/5): \e[0m" && read ww case $ww in
1)
a=`df -Th |awk '{print $1,$2,$5}'` ##查询所有磁盘内存信息
echo "磁盘大小是使用率分别为: $a"
;;
2)
b=`free -h |grep 'Mem' |awk '{print $2,$3}'`
echo "内存大小和使用率分别为: $b"
;;
3)
c=`uptime |awk '{print $11,$12,$13}'`
echo "cpu 负载为: $c"
;;
4)
d=`uptime |awk '{print $3,$4}'`
echo "运行时间为: $d"
;;
5)
e=`uname -r`
echo "版本号为: $e"
;;
*)
echo "error select"
;;
esac
}
tree () {
f=`cat /etc/redhat-release |awk '{print $4}' |awk -F'.' '{print $1}'`
if [ $f -eq 7 ];then
echo "此版本为centos $f 的版本"
read -p "是否重新配置yum源 (y|n): " yn
if [ "$yn" = "y" ];then
yum install -y wget ntpdate net-tools vim bash-completion ShellCheck
systemctl stop firewalld
iptable -X && iptable -F && iptable -Z
systemctl disable firewalld
sed -ri s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
setenforce 0
cp /etc/yum.repos.d/* /tmp/ && rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum clean all && yum makecache fast
ntpdate -b ntp1.aliyun.com
else
echo "不需要重新配置yum源"
fi
fi
}
four () {
cat <<-EOF
"请输入您的选项"
1.修改主机名
2.配置静态ip
EOF
printf "\e[1;31m 请选择你想使用的功能(1/2): \e[0m" && read wen
case $wen in
1)
read -p "请输入你的主机名" name
hostnamectl set-hostname $name &&bash
;;
2)
cp /etc/sysconfig/network-scripts/ifcfg-ens33 /tmp/ifcfg-ens33.bak
read -p "请输入你的ip的末尾" ipname
echo "TYPE=Ethernet BOOTPROTO=static DEFROUTE=yes NAME=ens33 DEVICE=ens33 ONBOOT=yes IPADDR=192.168.229.$ipname PREFIX=24 GATEWAY=192.168.229.2 DNS1=223.5.5.5 DNS2=223.6.6.6" >/etc/sysconfig/network-scripts/ifcfg-ens33
systemctl restart network
;;
*)
echo "eroor select"
;;
esac
}
five () {
if rpm -qa |grep "mysql" |egrep -v grep > /dev/null
then
echo cunzai!
else
echo no !
sed -ri s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
systemctl stop firewalld && systemctl disable firewalld
yum -y groupinstall "Development Tools"
cd /usr/local/src/
wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
rpm -ivh mysql80-community-release-el7-1.noarch.rpm
sed -ri 21s/enabled=0/enabled=1/g /etc/yum.repos.d/mysql-community.repo
sed -ri 28s/enabled=1/enabled=0/g /etc/yum.repos.d/mysql-community.repo
yum -y install mysql-community-server
systemctl start mysqld && systemctl enable mysqld
grep "password" /var/log/mysqld.log
fi
}
six (){
if rpm -qa |grep "nginx" |egrep -v grep > /dev/null
then
echo cunzai!
else
echo no !
yum -y install gcc gcc-c++ pcre pcre-devel
yum -y install nginx
fi
}
liu
printf "\e[1;31m 请选择你想要实现的功能(1/2/3/4/5/6): \e[0m" && read sb
case $sb in
1)one
;;
2)two
;;
3)tree
;;
4)four
;;
5)five
;;
6)six
;;
*)
echo "eroor select"
esac
1.3 shell编程特点
补全
历史
别名
快捷键
前后台作业
重定向
管道
命令排序执行
; && ||
通配符
{
} ? *
正则表达式
脚本
查看历史命令
history /etc/profile 下的historysize 可以修改
调用历史命令
上下健
!关键字
!历史命令行号
!! 执行上一条命令
!$ 上一条命令
alt+.
esc . 上一条命令的最后一个参数
Ctrl+r 在历史命令中查找,输入关键字调出之前的命令
关键字+pgup/phdn 可以切换关键字相关的历史命令
显示历史命令执行时间:
1.设置变量:
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S"
2.再次执行history查看结果
别名
查看别名
alias
设置别名
临时设置
Ctrl+a 切换到命令行开始(跟home一样,但是home在某些unix环境下无法使用) Ctrl+e 切换到命令行末尾 Ctrl+u 清除剪切光标之前的内容 Ctrl+k 清除剪切光标之后的内容 ctrl+y 粘贴刚才
锁删除的字符 Ctrl+r 在历史命令中查找,输入关键字调出之前的命令
*,?,[],{
}
例:
字符 含义 实例
* 匹配 0 或多个字符 a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。
? 匹配任意一个字符 a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。
[list] 匹配 list 中的任意单一字符 a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。
[!list] 匹配 除list 中的任意单一字符 a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。
[^list] 匹配 除list 中的任意单一字符 a[^0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。
[c1-c2] 匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z] a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。
{
string1,string2,...} 匹配 sring1 或 string2 (或更多)其一字符串 a{
abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。
1.4shell脚本规范
[root@master1 ~]# vim helloworld.sh
---.sh代表这个文件是个shell脚本,拓展名后缀,如果省略.sh则不易判断该文件是否为shell脚本
1. #!/usr/bin/env bash ---shebang蛇棒, 解释器, 翻译
2. #
3. # Author: tiger
3. # Email: tigerfive@163.com
4. # Github: https://github.com/tigerfive ---这就是注释, 你没看错
5. # Date: 2019/**/**
6.
7. printf "hello world\n"
[root@master1 ~]# sh helloworld.sh #sh命令是启动脚本
hello world
[root@master1 ~]# ./helloworld.sh #./ 也是启动sh 脚本命令
第一行: “#!/usr/bin/env bash”叫做shebang, shell语法规定shell脚本文件第一行为整个文件的解释器
第二行: 为“#”开头的行为注释行默认不会被程序所读取, 用来说明文件及标定所属人员使用, 也可用来解释程序
第七行: 为格式化打印语句printf, printf可以把后面的“hello world”打印到指定的终端中, \n为换行符
1.5 脚本运行方式
1.创建脚本文件
指定命令解释器
注释
编写bash指令集合
2.修改权限
bash
#./scripts
#/shelldoc/scripts
#. ./scripts 使用当前shell执行
#source ./scripts 使用当前shell执行 比如cd /tmp会改变当前shell环境,但是其他的方式不会
#bash scripts
(cmds) 表示开启子shell
# pwd
/root/shell
# (cd /tmp;touch test;)
# ls /tmp/test
/tmp/test
# pwd
/root/shell
子shell能够继承父shell的一些属性,但是子shell不能够反过来改变父shell的属性
子shell的好处之一可以将复杂的任务分成多个小任务,并行处理,加快执行速度。
所有shell的父shell父进程:init
{
cmds} 不开启子shell
# {
cd /tmp;touch test1; }
# pwd
/tmp
•sh –x script
这将执行该脚本并显示所有变量的值
•sh –n script
不执行脚本只是检查语法模式,将返回所有错误语法
•sh –v script
执行脚本前把脚本内容显示在屏幕上
1.6变量的类型 【要点】
变量的类型:
1. 自定义变量
定义变量: 变量名=变量值 变量名必须以字母或下划线开头,区分大小写 ip1=192.168.2.115
引用变量: $变量名 或 ${
变量名}
查看变量: echo $变量名 set(所有变量:包括自定义变量和环境变量)
取消变量: unset 变量名
作用范围: 仅在当前shell中有效
[root@master ~]# a=8
[root@master ~]# echo $a
8
[root@master ~]# echo $a2
[root@master ~]# echo ${a}2
82
环境变量:shell在开始执行时已经定义好的
env 查看所有环境变量
set 查看所有变量
环境变量拥有可继承性:export之后就拥有继承性
export 导出变量(作用范围)
临时生效
永久生效
写道4个登陆脚本中 ~/.bashrc ~/profile
更好放在/etc/profile.d/* 下建立独立的环境变量配置文件
jdk
常用环境变量:USER UID HOME HOSTNAME PWD PS1 PATH
PATH:存储所有命令所在的路径
3. 位置变量
$1 $2 $3 $4 $5 $6 $7 $8 $9 ${
10}
4. 预定义变量
$0 脚本名
$* 所有的参数
$@ 所有的参数
$# 参数的个数
$$ 当前进程的PID
$! 上一个后台进程的PID
$? 上一个命令的返回值 0表示成功
示例1:
# vim test.sh
echo "第2个位置参数是$2"
echo "第1个位置参数是$1"
echo "第4个位置参数是$4"
echo "所有参数是: $*"
echo "所有参数是: $@"
echo "参数的个数是: $#"
echo "当前进程的PID是: $$"
echo '$1='$1
echo '$2='$2
echo '$3='$3
echo '$*='$*
echo '$@='$@
echo '$#='$#
echo '$$='$$
了解$*和$@区别
变量的赋值方式:
1. 显式赋值
变量名=变量值
示例:
ip1=192.168.229.61
school="BeiJing 1000phone"
today1=`date +%F`
today2=$(date +%F)
2. read 从键盘读入变量值
read 变量名
read -p "提示信息: " 变量名
read -t 5 -p "提示信息: " 变量名
read -n 2 变量名
示例一:ping,采用变量写一个,判断ip地址能否ping通
[root@master ~]# cat ping2.sh
#!/bin/bash
read -p "Input IP: " ip
ping -c2 $ip &>/dev/null
if [ $? = 0 ];then
echo "host $ip is ok"
else
echo "host $ip is fail"
fi
[root@master ~]# sh ping2.sh
Input IP: 192.168.229.61 #输入您需要ping的IP地址
host 192.168.229.61 is ok #显示ok则以完成测试
定义或引用变量时注意事项:
" " 弱引用
' ' 强引用
[root@master ~]# school=1000phone
[root@master ~]# echo "${school} is good"
1000phone is good
[root@master ~]# echo '${school} is good'
${
school} is good
` ` 命令替换 等价于 $() 反引号中的shell命令会被先执行
[root@master ~]# touch `date +%F`_file1.txt
[root@master ~]# touch $(date +%F)_file2.txt
[root@master ~]# disk_free3="df -Ph |grep '/$' |awk '{print $4}'" 错误
[root@master ~]# disk_free4=$(df -Ph |grep '/$' |awk '{print $4}')
[root@master ~]# disk_free5=`df -Ph |grep '/$' |awk '{print $4}'`
1. 整数运算
方法一:expr
expr 1 + 2
expr $num1 + $num2 + - \* / %
方法二:$(())
echo $(($num1+$num2)) + - * / %
echo $((num1+num2))
echo $((5-3*2))
echo $(((5-3)*2))
echo $((2**3))
sum=$((1+2)); echo $sum
方法三:$[]
echo $[5+2] + - * / %
echo $[5**2]
方法四:let
let sum=2+3; echo $sum
let i++; echo $i
2. 小数运算
echo "2*4" |bc
echo "2^4" |bc
echo "scale=2;6/4" |bc
awk 'BEGIN{print 1/2}'
echo "print 5.0/2" |python
2.浮点运算:
bash本身不能做小数计算:需要bc命令转换
#echo "2*4" | bc
#echo "2^4" | bc
#echo "scale=2;6/4" | bc
scale: 精度
#awk 'BEGIN{print 1/2}'
#echo "print 5.0/2" | python
计算我的信用卡一个月的利息,假设我欠10000块钱
#!/bin/bash
m=$( echo 5/10000|bc -l)
#因为shell不支持小数,所以要用bc转换一下
sum=10000
for i in {
1..365}
do
sum=$(echo $sum+$sum*$m | bc )
echo $sum
done
echo $sum
3.变量引用
转义:\
为了显示元字符,需要引用。当一个字符被引用时,其特殊含义被禁止
把有意义的变的没意义,把没意义的变的有意义
\n \t \r
# echo -e '5\\n6\n7'
5\n6
7
# yum install httpd mysql -y
# yum groupinstall KDE\ Plasma\ Workspaces
完全引用:'' //强引 硬引
部分引用:"" //弱引 软引
#ls -lh --sort=size | tac
#echo hello;world
#echo you own $1250
例子: 从这个例子举出的是,弱引和强引的区别,强引打印原文,弱引打印变量
[root@master ~]# num=15
[root@master ~]# echo 1793班有$num个女生
1793班有15个女生
[root@master ~]# echo "1903班有$num个女生"
1903班有15个女生
[root@master ~]# echo '1903班有$num个女生'
1903班有$num个女生
读取用户标准输入:read 【重点参数】
read:功能就是读取键盘输入的值,并赋给变量
#read -t 5 var
#read -p "提示信息" var
示例:
#!/bin/bash
read system setting network
echo "This is computer function $system"
echo "This is computer function $setting"
echo "This is computer function $network"
示例:2
暂停用户输入:
[root@master ~]# shiyan.sh
read -p "如果你同意以上协议请按回车继续! " answer
echo 这是下面的操作了
sleep 1
echo 这是下面的操作了
sleep 1
echo 这是下面的操作了
sleep 1
echo 这是下面的操作了
sleep 1
echo 这是下面的操作了
[root@master ~]# sh shiyan.sh
如果你同意以上协议请按回车继续!
这是下面的操作了
这是下面的操作了
这是下面的操作了
这是下面的操作了
这是下面的操作了
示例3:
[root@master ~]# vim shiyan2.sh
#!/bin/bash
read -p "Do you want to continue [Y/N]? " answer
case $answer in
Y|y)
echo "fine ,continue";;
N|n)
echo "ok,good bye";;
*)
echo "error choice";;
esac
exit 0
[root@master ~]# sh shiyan2.sh
Do you want to continue [Y/N]? Y
fine ,continue
[root@master ~]# sh shiyan2.sh
Do you want to continue [Y/N]? N
ok,good bye
-s 选项
能够使read命令中输入的数据不显示在监视器上(实际上,数据是显示的,只是read命令将文本颜色设置成与背景相同的颜色
#!/bin/bash
read -s -p "Enter your password: " pass
echo "your password is $pass"
exit 0
取消屏幕回显:
stty -echo
stty echo
变量长度
[root@master ~]# a=123
[root@master ~]# echo ${#a} # 表示$var的长度
3
变量嵌套
[root@master ~]# a=8
[root@master ~]# name8=9
[root@master ~]# eval echo \$name$a
9
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·~·~~~~~~~~~~~~~~~~~~~~~~~~~~~~
示例4: 【这个脚本参数内容需要熟记,后续经常用到的】
[root@master ~]# vim shiyan4.sh #操作选项脚本,简单实现
#!/bin/bash
echo -e '1.配置yum客户端'
echo 2.添加A记录
echo 3.一键安装lamp环境
echo '4.一键配置静态IP'
read -p "请选择你想使用的功能(1/2/3/4):" num
con_ip(){
echo 这是配置IP地址的小工具
}
case $num in
1):;;
2):;;
3):;;
4)con_ip;;
*):;;
esac
[root@master ~]# sh shiyan4.sh
1.配置yum客户端
2.添加A记录
3.一键安装lamp环境
4.一键配置静态IP
请选择你想使用的功能(1/2/3/4):1
[root@master ~]# sh shiyan4.sh
1.配置yum客户端
2.添加A记录
3.一键安装lamp环境
4.一键配置静态IP
请选择你想使用的功能(1/2/3/4):2
[root@master ~]#
1.7 i++和++i
i++ 和 ++i (了解)
对变量的值的影响:
[root@master ~]# i=1
[root@master ~]# let i++
[root@master ~]# echo $i
2
[root@master ~]# j=1
[root@master ~]# let ++j
[root@master ~]# echo $j
2
对表达式的值的影响:
[root@master ~]# unset i
[root@master ~]# unset j
[root@master ~]# i=1
[root@master ~]# j=1
[root@master ~]# let x=i++ 先赋值,再运算
[root@master ~]# let y=++j 先运算,再赋值
[root@master ~]# echo $i
2
[root@master ~]# echo $j
2
[root@master ~]# echo $x
1
[root@master ~]# echo $y
2
二.shell变成
1.shell条件测试
测试 test 条件 条件为真返回 0,条件为假返回 1 【这个必须要记住,0为真,1为假】 [ 条件 ] test能够理解3中类型的表达式 1.文件测试 2.字符串比较 3.数字比较 字符串 -n STRING the length of STRING is nonzero -z STRING the length of STRING is zero STRING1 = STRING2 the strings are equal STRING1 != STRING2 the strings are not equal 数字 【重点参数】 eq 等于equal ne 不等于 ge 大于等于 gt 大于 le 小于等于 lt 小于 文件 -f 存在且是普通文件 -d 存在且是目录 -l 存在且是符号链接 -b 块设备 -c 字符设备 -e 文件存在 -r -w -x file1 -nt file2 file1 比 file2 新(修改时间) file1 -ot file2 file1 比 file2 旧(修改时间) ========= 格式1: test 条件表达式 格式2: [ 条件表达式 ] 格式3: [[ 条件表达式 ]] man test ===文件测试 [ 操作符 文件或目录 ] [root@master ~]# test -d /home [root@master ~]# echo $? 0 #零说明改目录存在 [root@master ~]# test -d /home11111 [root@master ~]# echo $? 1 #一说明改目录存在 [root@master ~]# [ -d /home ] [ -e dir|file ] [ -d dir ] [ -f file ] 是否存在,而且是文件 [ -r file ] 当前用户对该文件是否有读权限 [ -x file ] [ -w file ] [ -L file ] [root@master ~]# [ ! -d /ccc ] && mkdir /ccc [root@master ~]# [ -d /ccc ] || mkdir /ccc ===数值比较 [ 整数1 操作符 整数2 ] 【重点】 [ 1 -gt 10 ] 大于 [ 1 -lt 10 ] 小于 [ 1 -eq 10 ] 等于 [ 1 -ne 10 ] 不等于 [ 1 -ge 10 ] 大于等于 [ 1 -le 10 ] 小于等于 ===字符串比较 提示:使用双引号 [root@master ~]# [ $(id -u) -eq 0 ] || echo "必须是超级用户才能执行" [root@master ~]# [ "$USER" = "root" ];echo $? 0 [root@master ~]# [ "$USER" = "alice" ];echo $? 1 [root@master ~]# [ "$USER" != "alice" ];echo $? 0 [root@master ~]# [ 1 -lt 2 -a 5 -gt 10 ];echo $? 1 [root@master ~]# [ 1 -lt 2 -o 5 -gt 10 ];echo $? 0 [root@master ~]# [[ 1 -lt 2 && 5 -gt 10 ]];echo $? 1 [root@master ~]# [[ 1 -lt 2 || 5 -gt 10 ]];echo $? 0 [root@master ~]# [[ "$USER" =~ ^r ]];echo $? # 使用正则 正则只能使用[[]] 0 ==C语言风格的数值比较 [root@master ~]# ((1<2));echo $? 0 [root@master ~]# ((1==2));echo $? 1 [root@master ~]# ((1>2));echo $? 1 [root@master ~]# ((1>=2));echo $? 1 [root@master ~]# ((1<=2));echo $? 0 [root@master ~]# ((1!=2));echo $? 0 [root@master ~]# ((`id -u`>0));echo $? 1 [root@master ~]# (($UID==0));echo $? 0 示例1: 判断变量是不是数字: [root@master ~]# num1=123 [root@master ~]# num2=sss1414ss [root@master ~]# [[ "$num1" =~ ^[0-9]+$ ]];echo $? #判断是数字,则成功得出值为0 0 [root@master ~]# [[ "$num1" =~ ^[0-9]+$ ]];echo $? #判断结果为英文加数字。得出结果是错误的 1 示例2:判断是否输入的是一个数值 [root@master ~]# vim shiyan5.sh #!/bin/bash #判断用户输入的是否是数字 read -p 标签:
ge在线ph变送器