Shell-day01
1. Shell的课程大纲
Shell脚本必须要会,并且要精通。
1. Shell的基本概述
2. Shell的变量
3. Shell的数值运算
4. Shell的流程控制 if ;then fi
5. Shell的循环语句 for while
6. Shell的数组函数
7. Shell的正则表达式
Grep Sed Awk 命令的使用 Awk数组
8. Shell练习题 100多道练习题
2. 什么是Shell
Shell是一个命令解释器
Shell分为交互式和非交互式
$- 通过此变量可以获取到你的Shell的执行方式是交互式还是非交互式
#交互式
[root@shell ~]# echo $-
himBH
#非交互式
[root@shell ~]# vim test.sh
[root@shell ~]# cat test.sh
#!/bin/bash
echo $-
[root@shell ~]# sh test.sh
hB
h hashall #Shell会记录你执行过的命令路径,避免每次都要查询
i interactive #这个选项就是说明你是一个交互式Shell
m monitor #打开监控模式, 通过监控去控制进程的生命周期
B braceexpand #大括号扩展 { }
H history #命令的历史记录
3. 什么是Shell脚本
1. 系统的命令的堆积,按照顺序执行
2. 特定的格式 + 特定的语法 + 系统的命令 = 文件
3. 建议以.sh为结尾 .py
4. 为什么要学习Shell编程
运维人员必须要会
提升你的工作效率
减少不必要的重复性的工作
5. 学习Shell编程需要哪些知识
1. 对vim能够熟练的使用 熟悉.vimrc的配置
2. 要有linux的命令基础, 至少要掌握80个以上的常用命令并能够熟练使用
3. 要熟练掌握正则表达式及三剑客命令
4. 熟练常见的服务上面的配置 服务部署 优化 日志分析 排错
6. 如何学习好Shell
1. 阅读、模仿、阅读、模仿
2. 核心: 多练 多思考 坚持
3. 掌握Shell脚本的常见语法
4. 形成自己的脚本风格
5. 从简单做起,简单判断,简单循环
6. 学会分析问题,逐渐的形成编程思维
7. 变量名要规范,采用驼峰式语法 HostIp=xxx Host_Ip=xxx
8. 不要拿来主义,特别是针对新手
7. Shell脚本能干什么
1. 基础的配置 系统的初始化 系统更新 内核调整 网络 时区 优化
2. 安装软件程序 LNMP LAMP Nginx PHP MySQL Redis Rsync NFS
3. 配置的变更 Nginx PHP Redis MySQL conf 配置文件的变更
4. 业务的部署 Shell配合Git、jenkins实现自动化的部署 代码上线 回滚
5. 日常备份 脚本备份+定时任务 企业的备份
6. 信息采集 Zabbix监控 + Shell取值 对硬件 系统状态 服务
7. 日志分析 ELK 取值 排序 去重 统计 分析
8. 服务的扩容或者缩容
扩容: 添加集群节点 监控CPU 负载 内存 >80% 触发的动作 脚本
缩容: 减少集群节点 监控CPU 负载 内存 <20% 触发的动作 把某一个节点进行移除
8. Shell脚本的规范及习惯
1. 脚本放在统一的一个目录
/service/scripts/
2. 推荐使用vim进行编辑脚本 高亮显示
3. 以.sh为结尾
4. 脚本的第一行加上幻数 指定哪一个命令解释器进行解释脚本的命令 #!/bin/bash 默认以bash执行
5. 开头的#!/bin/bash #!称之为幻数 /bin/bash 就是命令解释器 必须放在代码的第一行 在其他行都是注释
6. 写脚本的时候附带作者和版权信息
7. 脚本注释 #后面的内容都是注释 最好不要使用中文 建议使用英文 禁止使用拼音
8. 成对的符号,要一次书写完成 "" {} '' []
9. 成对的语法格式,要一次书写完成 if ;then fi for i in do done
shell种类
[root@shell ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
[root@shell ~]# ll /etc/profile.d/
total 72
-rw-r--r--. 1 root root 771 2018-10-31 06:57 256term.csh
-rw-r--r--. 1 root root 841 2018-10-31 06:57 256term.sh
-rw-r--r--. 1 root root 660 2014-06-10 08:05 bash_completion.sh
-rw-r--r--. 1 root root 196 2017-03-25 00:39 colorgrep.csh
-rw-r--r--. 1 root root 201 2017-03-25 00:39 colorgrep.sh
-rw-r--r--. 1 root root 1741 2018-10-30 22:37 colorls.csh
-rw-r--r--. 1 root root 1606 2018-10-30 22:37 colorls.sh
-rw-r--r-- 1 root root 185 2020-04-20 17:07 color.sh
-rw-r--r--. 1 root root 80 2018-10-31 03:48 csh.local
-rw-r--r--. 1 root root 1706 2018-10-31 06:57 lang.csh
-rw-r--r--. 1 root root 2703 2018-10-31 06:57 lang.sh
-rw-r--r--. 1 root root 123 2015-07-31 08:47 less.csh
-rw-r--r--. 1 root root 121 2015-07-31 08:47 less.sh
-rw-r--r--. 1 root root 81 2018-10-31 03:48 sh.local
-rw-r--r--. 1 root root 105 2019-08-09 11:17 vim.csh
-rw-r--r--. 1 root root 269 2019-08-09 11:17 vim.sh
-rw-r--r--. 1 root root 164 2014-01-28 04:47 which2.csh
-rw-r--r--. 1 root root 169 2014-01-28 04:47 which2.sh
centos中的shell种类 (实际上是一种shell 它们之间是软链接关系)
root@shell /usr/bin]# ll
lrwxrwxrwx. 1 root root 4 2020-02-11 23:00 sh -> bash
[root@shell /bin]# ll
total 119828
lrwxrwxrwx. 1 root root 4 2020-02-11 23:00 sh -> bash
9. Shell脚本的执行方式
Shell脚本是从上到下、从左到右依次执行每一行的命令 执行完一条命令之后,再执行下一条命令。如果在脚本中遇到镶嵌脚本(子脚本)时,先执行子脚本,执行子脚本之后再去执行父脚本剩下的内容
执行方式:
1. bash script-name 或者 sh script-name #不需要执行权限,自己生成一个窗口环境执行命令
[root@shell /service/scripts/day01]# sh test.sh
[root@shell ~]# pstree
systemd─┬─VGAuthService
├─abrt-watch-log
├─abrtd
├─agetty
├─auditd───{auditd}
├─crond
├─dbus-daemon
├─master─┬─pickup
│ └─qmgr
├─polkitd───6*[{polkitd}]
├─rpcbind
├─rsyslogd───2*[{rsyslogd}]
├─sshd─┬─sshd───bash───sh───ping
│ └─sshd───bash───pstree
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
[root@shell ~]# mkdir -p /service/scripts
[root@shell /service/scripts/day01]# cat test.sh
#!/bin/bash
hostname
[root@shell /service/scripts/day01]# bash test.sh
shell
[root@shell /service/scripts/day01]# sh test.sh
shell
[root@shell /service/scripts/day01]# ll test.sh
-rw-r--r-- 1 root root 21 2020-04-20 11:28 test.sh
[root@shell /service/scripts/day01]# cat test.sh
#!/bin/bash
ping baidu.com &>/dev/null
# 可以通过过滤脚本中执行的命令查看进程
[root@shell ~]# ps aux | grep ping
root 7976 0.0 0.0 149968 1984 pts/0 S+ 11:29 0:00 ping baidu.com
# 也可以直接过滤 命令解释器查看正在执行的脚本进程
[root@shell ~]# ps aux | grep sh
root 7975 0.0 0.0 113176 1196 pts/0 S+ 11:29 0:00 sh test.sh
2. source script-name 或者 . script-name #不需要执行权限,将脚本中的代码放入到当前环境下执行
[root@shell /service/scripts/day01]# pstree
systemd─┬─VGAuthService
├─abrt-watch-log
├─abrtd
├─agetty
├─auditd───{auditd}
├─crond
├─dbus-daemon
├─master─┬─pickup
│ └─qmgr
├─polkitd───6*[{polkitd}]
├─rpcbind
├─rsyslogd───2*[{rsyslogd}]
├─sshd─┬─sshd───bash───pstree
│ └─sshd───bash───ping
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
[root@shell ~]# ps aux | grep source
root 8074 0.0 0.0 112708 976 pts/1 R+ 11:33 0:00 grep --color=auto source
[root@shell ~]# ps aux | grep ping
root 8070 0.0 0.0 149968 1984 pts/0 S+ 11:33 0:00 ping baidu.com
3. path/script-name 或者 ./script-name #路径执行 需要执行权限 自己生成一个窗口环境执行命令
[root@shell /service/scripts/day01]# ./test.sh
-bash: ./test.sh: Permission denied
[root@shell /service/scripts/day01]# /service/scripts/day01/test.sh
-bash: /service/scripts/day01/test.sh: Permission denied
[root@shell ~]# ps aux | grep ping
root 8099 0.0 0.0 149968 1984 pts/0 S+ 11:39 0:00 ping baidu.com
root 8103 0.0 0.0 112708 976 pts/1 S+ 11:39 0:00 grep --color=auto ping
[root@shell ~]# ps aux | grep test
root 8098 0.0 0.0 113176 1192 pts/0 S+ 11:39 0:00 /bin/bash /service/scripts/day01/test.sh
root 8105 0.0 0.0 112708 976 pts/1 R+ 11:39 0:00 grep --color=auto test
4. cat script-name | bash #不需要执行权限 自己生成一个窗口环境执行命令
[root@shell ~]# ps aux | grep test
root 8124 0.0 0.0 112708 976 pts/1 R+ 11:42 0:00 grep --color=auto test
[root@shell ~]# ps aux | grep ping
root 8122 0.0 0.0 149968 1984 pts/0 S+ 11:42 0:00 ping baidu.com
root 8126 0.0 0.0 112708 972 pts/1 R+ 11:42 0:00 grep --color=auto ping
5. bash < script-name 或者 sh < script-name #不需要执行权限 自己生成一个窗口环境执行命令
[root@shell ~]# ps aux | grep ping
root 8130 0.0 0.0 149968 1992 pts/0 S+ 11:43 0:00 ping baidu.com
root 8132 0.0 0.0 112708 976 pts/1 R+ 11:43 0:00 grep --color=auto ping
[root@shell ~]# ps aux | grep test
root 8134 0.0 0.0 112708 976 pts/1 R+ 11:43 0:00 grep --color=auto test
10. 登录式Shell和非登录式Shell
登录式Shell 通过用户和密码的方式进行登录进入的Shell
非登录式Shell 不需要用户和密码的方式进入的Shell bash
执行exit命令时, 可以退出登录式Shell和非登录式hell
执行logout命令时, 只能退出登录式Shell,不能退出非登录式Shell
脚本就是一个非登录式Shell
非登录式Shell不会执行/etc/profile这个文件
配置文件的执行顺序
/etc/profile
/etc/profile.d/*sh
/root/.bash_profile
/etc/bashrc
/root/.bashrc
登录式Shell的配置文件执行顺序
/etc/profile
/etc/profile.d/*sh
.bash_profile
.bashrc
/etc/bashrc
非登录式Shell的配置文件的执行顺序
[root@shell ~]# bash
.bashrc
/etc/bashrc
/etc/profile.d/*sh
11. Shell的变量介绍
什么是变量
就是传递数据的一种方法,
简单理解: 用一个固定的字符串去表示一个不固定的内容,便于后期引用
变量名的规范
采用驼峰法书写
变量的名称不要跟系统中的命令或者变量有冲突
名称要求: 字母、数字、下划线组成 尽量使用字母开头,变量名称最好具有一定的含义
ip=10.0.0.80
IP=xxxx
ip1=10.0.0.80
hostip=xxx
Hostip=xxxx
HostIp=xxxx
Host_Ip=xxxx
host_ip=xxxxxx
前面是变量名称 = 等号是赋值 后面的就是定义的值 等号两边不能存在空格。
变量的定义方式
1、用户自定义变量: 用户自己定义的变量
2、系统环境变量: 系统已经定义好的变量,变量记录的是操作系统的一些信息 全部是由大写字母组成的
全局变量 和 局部变量
3、位置参数变量: 向脚本中进行传递参数,变量名不能自己定义,变量的作用也是固定的 $1 $2
4、预定义变量: bash已经定义好的变量,变量名不能自己定义,变量的作用也是固定的,值不是自己设置的 $@ $* $? $0
12. 变量的定义实践
1. 用户自定义变量,只在当前环境生效
#定义变量
[root@shell ~]# Name=qls
[root@shell ~]# Name=qls qiudao #变量值出现空格时,使用引号引用起来
-bash: qiudao: command not found
[root@shell ~]# Name='qls qiudao'
[root@shell ~]# Name-1=qls #变量名不能出现短横岗
-bash: Name-1=qls: command not found
[root@shell ~]# Name1=qls
[root@shell ~]# 1Name=qls #不能以数字开头
-bash: 1Name=qls: command not found
#引用变量
[root@shell ~]# echo $Name
qls qiudao
[root@shell ~]# echo ${Name}
qls qiudao
[root@shell ~]# echo $Nameage
[root@shell ~]# echo $Name_age
[root@shell ~]# echo ${Name}_age
qls qiudao_age
[root@shell ~]# Num=10
[root@shell ~]# echo $Num% #%是特殊字符可以识别
10%
#查看所有的变量
set
#显示局部变量
[root@shell ~]# set | grep Name
Name='qls qiudao'
#显示全局变量和进程正在运行中的变量 显示系统的环境变量
[root@shell ~]# env | grep Name
[root@shell ~]# echo $USER
root
#取消变量
unset
[root@shell ~]# Name=qls
[root@shell ~]#
[root@shell ~]# unset Name
[root@shell ~]# echo $Name
单双引号和不加引号及反引号的区别
反引号,先执行反引号里面的命令,将执行的结果交给外面的命令 里面必须是命令
[root@shell ~]# Name=$(hostname)
[root@shell ~]# echo $Name
shell
[root@shell ~]# Name=`hostname`
[root@shell ~]# echo $Name
shell
单引号 强引用 单引号里面是什么,得到的也是什么
[root@shell ~]# Name='$(hostname)'
[root@shell ~]# echo $Name
$(hostname)
双引号 弱引用 里面是什么内容,也会得到什么内容 但是他会解析变量 解析特殊字符
[root@shell ~]# Name="$(hostname)"
[root@shell ~]# echo $Name
shell
不加引号 当变量的值出现空格时,不会将值看做是一个整体,不支持通配符
[root@shell ~]# Name=qls qiudao
-bash: qiudao: command not found
[root@shell ~]# Name={1..10}
[root@shell ~]# echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@shell ~]# echo $Name
{1..10}
[root@shell ~]# Name=hj
[root@shell ~]# echo $Name
hj
[root@shell ~]# echo $Name money is $10000000000
hj money is 0000000000
[root@shell ~]# echo "$Name money is $10000000000"
hj money is 0000000000
[root@shell ~]# echo '$Name money is $10000000000'
$Name money is $10000000000
[root@shell ~]# echo $Name money is '$10000000000'
hj money is $10000000000
[root@shell ~]# echo "$Name money is \$10000000000"
hj money is $10000000000
[root@shell ~]# echo $Name money is \$10000000000
hj money is $10000000000
系统环境变量 全局生效的
如何自定义环境变量 ,在当前环境下和子shell环境下生效
# 使用export 命令定义变量可以实现
[root@shell ~]# Name=qls
[root@shell ~]# echo $Name
qls
[root@shell ~]# vim test.sh
[root@shell ~]# cat test.sh
#!/bin/bash
echo $Name
[root@shell ~]# sh test.sh
[root@shell ~]# export Name=qls
[root@shell ~]# echo $Name
qls
[root@shell ~]# sh test.sh
qls
使用export命令只能在当前环境下和当前环境下的子shell环境生效,但是export命令设置的变量只能临时生效,退出登录后再次登录变量会失效。
只有将变量写入到环境变量配置文件中,才会全局生效 当前用户和所有用户生效
[root@shell ~]# echo $USER
root
[root@shell ~]# echo $UID
0
[root@shell ~]# echo $HOME
/root
[root@shell ~]# echo $HOSTNAME
shell
[root@shell ~]# echo $PWD
/root
[root@shell ~]# cd /opt/
[root@shell /opt]# echo $PWD
/opt
[root@shell /opt]# echo $SHELL
/bin/bash
位置变量
[root@shell ~]# cat test.sh
#!/bin/bash
echo $1 $2 $4
[root@shell ~]# sh test.sh
[root@shell ~]# sh test.sh 1 2 3
1 2
[root@shell ~]# sh test.sh 1 2 3 4
1 2 4
$1 $2 $3 .. $N ${10} 位置变量出现两位数的时候,需要使用花括号括起来
预定义的变量
$0 $* $@ $# $? $$
[root@shell /service/scripts/day01]# cat test.sh
#!/bin/bash
echo "当前Shell的脚本文件名为:$0"
echo "当前Shell运行的PID号为:$$"
echo "当前Shell的第一个位置变量为:$1"
echo "当前Shell的第二个位置变量为:$2"
echo "当前Shell的第三个位置变量为:$3"
echo "当前传递的所有位置参数为:$*"
echo "当前传递的所有位置参数为:$@"
echo "当前总共传递的位置参数的个数为:$#"
echo "上条命令的执行结果为:$?"
[root@shell /service/scripts/day01]# sh /service/scripts/day01/test.sh linux nginx php
当前Shell的脚本文件名为:/service/scripts/day01/test.sh
当前Shell运行的PID号为:8932
当前Shell的第一个位置变量为:linux
当前Shell的第二个位置变量为:nginx
当前Shell的第三个位置变量为:php
当前传递的所有位置参数为:linux nginx php
当前传递的所有位置参数为:linux nginx php
当前总共传递的位置参数的个数为:3
上条命令的执行结果为:0
[root@shell /service/scripts/day01]# cat test1.sh
#!/bin/bash
test() {
echo "未加引号,二者是相同的"
echo $*
echo $@
echo "加入引号对比"
for i in "$*"
do
echo $i
done
echo '###################'
for j in "$@"
do
echo $j
done
}
test linux nginx mysql
[root@shell /service/scripts/day01]# sh test1.sh
未加引号,二者是相同的
linux nginx mysql
linux nginx mysql
加入引号对比
linux nginx mysql
###################
linux
nginx
mysql
没有加入引号之前,两者是相同的
加入引号之后呢
$* 把参数作为一个字符串整体进行输出返回
$@ 把每个参数作为一个一个字符串返回
[root@shell /service/scripts/day01]# echo $(date +%F)
2020-04-20
[root@shell /service/scripts/day01]# touch qls{1..9}.txt
[root@shell /service/scripts/day01]# ll
total 8
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls1.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls2.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls3.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls4.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls5.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls6.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls7.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls8.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls9.txt
-rw-r--r-- 1 root root 280 2020-04-20 16:11 test1.sh
-rw-r--r-- 1 root root 451 2020-04-20 16:03 test.sh
[root@shell /service/scripts/day01]# tar czf qls.tar.gz *.txt
[root@shell /service/scripts/day01]# ll
total 12
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls1.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls2.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls3.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls4.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls5.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls6.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls7.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls8.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls9.txt
-rw-r--r-- 1 root root 177 2020-04-20 16:19 qls.tar.gz
-rw-r--r-- 1 root root 280 2020-04-20 16:11 test1.sh
-rw-r--r-- 1 root root 451 2020-04-20 16:03 test.sh
[root@shell /service/scripts/day01]# tar cvzf qls.tar.gz *.txt
qls1.txt
qls2.txt
qls3.txt
qls4.txt
qls5.txt
qls6.txt
qls7.txt
qls8.txt
qls9.txt
嵌套变量
[root@shell /service/scripts/day01]# File=$(tar czf qls.tar.gz $(find ./ -name "*.txt"))
[root@shell /service/scripts/day01]#
[root@shell /service/scripts/day01]#
[root@shell /service/scripts/day01]# echo $File
[root@shell /service/scripts/day01]# tar czf qls.tar.gz $(find ./ -name "*.txt")
[root@shell /service/scripts/day01]# ll
total 12
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls1.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls2.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls3.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls4.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls5.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls6.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls7.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls8.txt
-rw-r--r-- 1 root root 0 2020-04-20 16:19 qls9.txt
-rw-r--r-- 1 root root 180 2020-04-20 16:21 qls.tar.gz
-rw-r--r-- 1 root root 280 2020-04-20 16:11 test1.sh
-rw-r--r-- 1 root root 451 2020-04-20 16:03 test.sh
[root@shell /service/scripts/day01]# File=$(tar czvf qls.tar.gz $(find ./ -name "*.txt"))
[root@shell /service/scripts/day01]# echo $File
./qls1.txt ./qls2.txt ./qls3.txt ./qls4.txt ./qls5.txt ./qls6.txt ./qls7.txt ./qls8.txt ./qls9.txt