Day...1
大纲
基础变量 bash
shell执行方式 if判断 for循环 while循环 until循环
条件控制语句 exit continue break 函数 数组
1.Shell可以做什么?
1)安装操作系统 CentOS6.X 、CentOS7.X 手动方式安装 克隆方式
自动化安装、cobbler、kickstart 底层都是shell脚本实现
2)shell脚本可以优化
优化SSH、关闭Selinux、优化防火墙(Firewalld)、放行Nginx(80)、HTTPS(443)、SSH端口、zabbix监控(10051)数据库Mysql仅本地连接(127.0.0.1)、企业与个人需求放行的端口、加大文件描述符、时间同步(硬件时间clock、软件时间date)、默认YUM源......
3)安装服务
Nginx、Apache、Tomcat、PHP、MySQL、Redis、Mongo、docker.....
集群中,即有安装PHP5.4又有安装PHP7.1,可以写入shell脚本,自动化安装不同版本的服务
4)代码上线
shell脚本自动化发布、自动化回滚
5)zabbix监控
硬件、软件、进程、端口号、自定义监控......---> shell脚本+定时任务
6)日志分析
日志统计--->三剑客+定时任务+shell脚本
日志展示--->ELK
7)业务层面shell编写业务框架
8)辅助开发程序
python nohup python3.5 test.py & nohup.out 大量的日志,辅助清空
2.Shell用到的基础知识
1)vim编辑器快捷键
2)Linux常用命令,60个左右
3)三剑客 awk sed grep find
4)xshell、Crt 连接工具
3.Shell编程
1)重点掌握的内容 变量、判断、bash
2)看懂、读懂shell脚本
3)判断 前面的脚本进行完善
4)写简单的脚本项目 随机点餐 会员办理服务 会员账号 密码 密码丢失
5)Shell编程或完善的文档
6)Shell编程,解决企业中大部分的shell问题
4.编程语言
Shell、Python、Go、ruby、c、c++、javascript、perl......
编译型语言: 只编译一次,后面直接运行代码即可
解释型语言: 运行一次,解释一次
解释型语言目前不一定比编译型语言慢,优化后,也很快,甚至比编译还快
shell和python区别:
shell 处理系统底层的内容,程序运行、启动、系统运行--->用于shell脚本实现
python、php主要作用搭建web: 自动化CMDB、处理底层的效率低
5.Shell
Linux中默认的shell是: bash
输入输出传达到bash,bash翻译命令给内核,内核驱动相应的硬件完成工作,完成结果反馈给用户
bash两种工作方式:
交互式: 使用者输入命令,bash执行命令,执行完,使用者退出,bash结束
非交互式: 把命令写入到文件中,bash执行文件中的内容,执行到末尾 bash结束
通过xshell登录到系统中,当前的位置属于父shell,所有的文件在执行时调用子shell执行,执行结束子shell退出
6.Shell脚本
命令的堆积
将命令写入到一个文本中 shell脚本 语法格式 if判断 for循环 while 函数 数组......
7.Shell脚本入门、规范
1)脚本统一存放固定的目录 /server/scripts ,统一化是为自动化铺垫
2)脚本命令结尾以.sh结尾,LINUX中的后缀给自己看,区分文件用
3)shell脚本的开头 写解释器 #!/bin/bash或#!/bin/sh
# sh 为 bash 的软连接 [root@shell:~]# ll /bin/bash -rwxr-xr-x. 1 root root 964536 Apr 1 2020 /bin/bash [root@shell:~]# ll /bin/sh lrwxrwxrwx. 1 root root 4 Aug 26 01:35 /bin/sh -> bash
4)脚本最好有注释、说明 #Author 时间 电话 QQ...
5)说明尽量用英文,最好用中文
6)成对的符号、循环语句一次性书写完毕
8.第一个shell脚本
1 2 3 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo "Hello World!" |
执行脚本的三种常用的方式:
注意:子shell生命周期特别短暂,父shell相当于在命令行输入
1.bash或sh方式,通过解释器执行脚本--->在子shell中执行命令
1 2 3 4 | [root@shell /server/scripts ] # sh test.sh Hello World! [root@shell /server/scripts ] # bash test.sh Hello World! |
2.路径方式 全路径或当前路径,必须给x权限,开机自动加载一个shell脚本 /etc/rc.local--->在子shell中执行命令
1 2 3 4 5 | [root@shell /server/scripts ] # chmod +x test.sh [root@shell /server/scripts ] # /server/scripts/test.sh Hello World! [root@shell /server/scripts ] # ./test.sh Hello World! |
3.source或 . 方式--->在父shell中执行命令
1 2 3 4 | [root@shell /server/scripts ] # . test.sh Hello World! [root@shell /server/scripts ] # source test.sh Hello World! |
4.子shell与父shell证明,子shell调用周期特别短暂,调用结束失效,父shell调用时间长
1 2 3 4 5 6 7 8 9 10 | [root@shell ~] # cat 1.sh #!/bin/bash name=majunnan [root@shell ~] # sh 1.sh # 在子shell中执行 [root@shell ~] # echo $name # 显示变量 # 空 [root@shell ~] # source 1.sh # 在父shell中执行 [root@shell ~] # echo $name # 显示变量 majunnan |
5.使用其他shell的执行方式
1 2 3 4 5 6 7 8 9 10 11 12 | [root@shell /server/scripts ] # cat test.sh pwd [root@shell /server/scripts ] # cat test.sh|bash /server/scripts [root@shell /server/scripts ] # echo ls ls [root@shell /server/scripts ] # echo ls|bash test .sh # 读入的方式,把文件中的内容传入到bash中,一行一行读取,一边读取,一边执行 [root@shell /server/scripts ] # bash < test.sh /server/scripts |
9.shell的变量基础
什么是变量?
用一个固定的字符串表示不固定的值,称为变量
变量的种类: 查看全局变量 env
环境变量(全局变量) 针对全局生效,对所有的shell生效,例:PS1、PATH、LANG
普通变量(局部变量) 针对当前某个shell生效
按照生命周期区分:
永久的: 写入/etc/profile,每次使用xshell连接系统,都会自动加载/etc/profile
临时的: 使用export声明即可
添加export区别: 对当前打开窗口的所有shell生效 (无论父shell、子shell)
不加export区别: 只对当前的shell生效(即使父shell,资源也无法下发)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [root@shell ~] # age=18 # 只对当前父shell有效 [root@shell ~] # echo $age 18 [root@shell ~] # cat 1.sh echo $age [root@shell ~] # sh 1.sh 空 # 只对上面的父shell生效,未对当前子shell生效 [root@shell ~] # export name=nn # 对当前打开的所有窗口生效 [root@shell ~] # echo $name nn [root@shell ~] # cat 2.sh echo $name [root@shell ~] # sh 2.sh nn [root@shell ~] # echo $name # 另开一台xshell窗口,$name未生效 空 |
案例: rsync -avz hosts rsync_backup@10.0.0.41::backup
10.定义环境变量name=nn
1 2 3 4 5 | [root@shell ~] # _name=nn [root@shell ~] # echo $_name nn [root@shell ~] # 1name=mm - bash : 1name=mm: command not found |
1 2 3 4 | NAME_AGE= 全大写 系统默认的变量都是大写 Name_Age 大驼峰语法 name_Age 小驼峰语法 name_age 全小写 |
1.字符串定义:必须是连续的字符串,值不允许有空格
双引号和单引号的区别:双引号解析变量,单引号所见即所得,不能解析变量,不加引号可以解析变量
1 2 3 4 5 6 7 | [root@shell ~] # name=majunnan # 连续,不允许有空格 [root@shell ~] # name='I am majunnan' # 使用单引号,允许有空格 [root@shell ~] # echo $name I am majunnan [root@shell ~] # name="I am majunnan" # 使用双引号,允许有空格 [root@shell ~] # echo $name I am majunnan |
1 2 3 | [root@shell ~] # age="12 23 432" [root@shell ~] # echo $age 12 23 432 |
1 2 3 4 5 6 7 8 9 10 | [root@shell ~] # date +%F-%H-%M-%S 2021-10-18-15-39-36 [root@shell ~] # time=`date +%F-%H-%M-%S` [root@shell ~] # echo $time 2021-10-18-15-40-03 [root@shell ~] # echo $time # 不会变,time成为定值,调用time的值是固定的 2021-10-18-15-40-03 [root@shell ~] # time=$(date +%F-%H-%M-%S) # $()与``相同 [root@shell ~] # echo $time 2021-10-18-15-43-12 |
时间是固定,每次调用时间都相同
1 2 3 4 5 6 7 8 9 | [root@shell ~] # cat 1.sh #!bin/bash time =` date +%F-%H-%M-%S` echo $ time sleep 2 echo $ time [root@shell ~] # sh 1.sh 2021-10-18-15-44-45 2021-10-18-15-44-45 |
1 2 3 4 5 6 7 8 9 | [root@shell ~] # cat 1.sh #!bin/bash time = 'date +%F-%H-%M-%S' echo `$ time ` sleep 2 echo `$ time ` [root@shell ~] # sh 1.sh 2022-09-05-14-57-14 2022-09-05-14-57-16 |
1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@shell ~] # ip=`ifconfig eth0|awk 'NR==2{print $2}'` [root@shell ~] # echo $ip 10.0.0.7 [root@shell ~] # dir=$ip_$time [root@shell ~] # echo $dir 2021-10-18-15-43-53 # IP没有,没办法分辨IP与时间 [root@shell ~] # dir=${ip}_${time} # 使用{}分开两个变量 [root@shell ~] # echo $dir 10.0.0.7_2021-10-18-15-43-53 [root@shell ~] # mkdir $dir [root@shell ~] # ll total 4 drwxr-xr-x 2 root root 6 Oct 18 15:50 10.0.0.7_2021-10-18-15-43-53 |
当shell脚本中出现2条以上相同的命令,写成变量
11.核心位置变量
$0 获取shell脚本的名称,执行如果带全路径,则$0带全路径*****
$n n为数字,从1开始,$1为脚本的第一个参数,从$9往后,需要加${10} *****
$# 获取脚本传参的总个数,针对传入的个数进行判断*****
$* 获取脚本传参的所有的参数,在循环体中不同,加上双引号视为单个字符串
$@ 获取脚本传参的所有的参数,在循环体中不同,加上双引号视为独立参数
$? 获取上一条命令的返回值,0为成功,非0失败*****
$$ 获取脚本的PID进程号,当有多个相同名称的shell环境中使用**
$! 获取上一个在后台运行脚本的PID号,测试常用**
$_ 获取脚本的最后一个参数或是某个东西 类似esc .
$0:获取shell脚本名称
1 2 3 4 5 6 7 8 9 10 11 12 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $0 [root@shell /server/scripts ] # sh test.sh test .sh [root@shell /server/scripts ] # /server/scripts/test.sh /server/scripts/test .sh # 让脚本给予提示,如何使用脚本 [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $0 echo $ "Usage: $0 {start|stop|status|restart|force-reload}" |
$0在Linux脚本中的使用方法:
1 2 3 4 5 6 7 8 9 10 11 | [root@shell /server/scripts ] # /etc/init.d/network Usage: /etc/init .d /network {start|stop|status|restart|force-reload} <br> # 过滤$0,使用撬棍转译或单引号所见即所得,不让他代表特殊含义 [root@shell /server/scripts ] # grep \$0 /etc/init.d/network $0 stop $0 start echo $ "Usage: $0 {start|stop|status|restart|force-reload}" [root@shell /server/scripts ] # grep '$0' /etc/init.d/network $0 stop $0 start echo $ "Usage: $0 {start|stop|status|restart|force-reload}" |
basename 只获取脚本的名称
1 2 | [root@shell /server/scripts ] # basename /server/scripts/test.sh test .sh |
$n 脚本的参数:
1 2 3 4 5 6 7 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $1 [root@shell /server/scripts ] # sh test.sh mm mm [root@shell /server/scripts ] # sh test.sh mm jj nn mm |
序列传参:从$9往后,需要加${10}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $3 [root@shell /server/scripts ] # sh test.sh {A..Z} C [root@shell /server/scripts ] # sh test.sh {1..10} 3 [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 [root@shell /server/scripts ] # sh test.sh {a..z} a b c d e f g h i a0 a1 # 出现错误,只能识别$1 [root@shell /server/scripts ] # cat test.sh # 加上{},使10、11成为一体 #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} [root@shell /server/scripts ] # sh test.sh {a..z} a b c d e f g h i j k |
$#获取脚本传参的总个数:
1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} echo $ # [root@shell /server/scripts ] # sh test.sh a b c a b c 3 [root@shell /server/scripts ] # sh test.sh {a..z} a b c d e f g h i j k 26 [root@shell /server/scripts ] # sh test.sh {1..10000} 1 2 3 4 5 6 7 8 9 10 11 10000 |
1 2 3 4 5 6 7 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo name=$1 echo age=$2 [root@shell /server/scripts ] # sh test.sh mm 18 name=mm # 此时显示mm只是代表字符串,未对name进行赋值 age=18 # 此时显示18也只是代表字符串,未对age进行赋值 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [root@shell ~] # [ 10 -eq 10 ] # 10等于10 [root@shell ~] # echo $? # 查看运行的结果,如果结果返回等于0,则上一条运行结果成立 0 [root@shell ~] # [ 10 -ne 10 ] # 10不等于10 [root@shell ~] # echo $? # 查看运行的结果,如果结果返回不等于0,则上一条运行结果不成立 1 [root@shell /server/scripts ] # cat test.sh #!/bin/bash [ $ # -ne 2 ] && echo "请输入两个参数" && exit # 参数总个数不为2,输出文字并退出 echo name=$1 echo age=$2 [root@shell /server/scripts ] # sh test.sh test # 输入一个参数时,输出文字,退出 请输入两个参数 [root@shell /server/scripts ] # sh test.sh test 18 name= test age=18 |
$* $@:获取脚本传参的所有参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | [root@shell /server/scripts ] # cat test.sh name=$1 age=$2 $* $@ [root@shell /server/scripts ] # sh test.sh {1..10} name=1 age=2 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 [root@shell /server/scripts ] # sh test.sh {a..z} name=a age=b a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z |
测试$* $@在循环体中加双引号区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [root@shell /server/scripts ] # set -- "I am" majunnan # 设置变量 [root@shell /server/scripts ] # echo $* I am majunnan [root@shell /server/scripts ] # echo $@ I am majunnan [root@shell /server/scripts ] # echo "$@" I am majunnan [root@shell /server/scripts ] # echo "$*" I am majunnan [root@shell /server/scripts ] # for i in $*;do echo $i;done I am majunnan [root@shell /server/scripts ] # for i in $@;do echo $i;done I am majunnan [root@shell /server/scripts ] # for i in "$*";do echo $i;done I am majunnan # 加双引号,视为单个字符串 [root@shell /server/scripts ] # for i in "$@";do echo $i;done I am # 加双引号,视为独立个体 majunnan |
$?:获取上一条命令的返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [root@shell /server/scripts ] # ll [root@shell /server/scripts ] # echo $? 0 [root@shell /server/scripts ] # llllllllllllll bash : llllllllllllll: command not found [root@shell /server/scripts ] # echo $? 127 [root@shell ~] # ping -c1 -W1 www.baidu.com &>/dev/null [root@shell ~] # echo $? 0 [root@shell ~] # cat ping.sh #!/bin/bash ping -c1 -W1 $1 &> /dev/null [ $? - eq 0 ] && echo "$1 通的" || echo "$1 不通" [root@shell ~] # sh ping.sh www.baidu.com www.baidu.com 通的 [root@shell ~] # sh ping.sh www.baidu.commmmmm www.baidu.commmmmm 不通 [root@shell ~] # sh ping.sh 10.0.0.5 10.0.0.5 不通 [root@shell ~] # sh ping.sh 10.0.0.1 10.0.0.1 通的 |
$$ 获取脚本的PID进程号,当有多个相同名称的shell环境中使用
1 2 3 4 5 6 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $$ # 显示当前进程PID,当多人登录使用一个服务时,可知自己进程PID [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $$ > /tmp/nginx_pid # 将当前的PID号写入文本中,可查看确定自己使用的服务 |
$! 获取上一个在后台运行脚本的PID号,测试常用**
1 2 3 4 5 6 | [root@shell ~] # cat test.sh #!/bin/bash echo $$ > /tmp/nginx_pid [root@shell ~] # sh test.sh [root@shell ~] # kill -9 $! kill : usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec] |
$_ 获取脚本的最后一个参数或是某个东西 类似esc .
1 2 3 4 5 6 | [root@shell ~] # ll 1234567 89 10 ls : cannot access 1234567: No such file or directory ls : cannot access 89: No such file or directory ls : cannot access 10: No such file or directory [root@shell ~] # echo $_ # 上一行输入最后一个是10,所以取10 10 |
12.脚本传参的三种方式
第一种方式:直接传参
1 2 3 4 5 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash echo $1 $2 [root@shell /server/scripts ] # sh test.sh mm 100 mm 100 |
第二种方式:赋值传参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash name=$1 age=$2 echo $name echo $age [root@shell /server/scripts ] # sh test.sh mm 200 mm 200 [root@shell /server/scripts ] # cat test.sh #!/bin/bash name=$1 age=$2 echo 姓名: $name echo 年龄: $age [root@shell /server/scripts ] # sh test.sh nn 100 姓名: nn 年龄: 100 |
第三种方式:read读入,交互式
1 2 3 4 5 6 7 8 9 10 11 12 | [root@shell /server/scripts ] # read name nn # 写入nn [root@shell /server/scripts ] # echo $name nn # 出现nn [root@shell /server/scripts ] # read -p "请输入你的姓名" name 请输入你的姓名nn # 写入nn [root@shell /server/scripts ] # echo $name nn # 出现nn [root@shell /server/scripts ] # read -p "请输入你的姓名: " name 请输入你的姓名: HEHE # 写入HEHE [root@shell /server/scripts ] # echo $name HEHE # 出现HEHE |
read第一种书写方式:一个一个
1 2 3 4 5 6 7 8 9 10 11 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash read -p "请输入你的姓名: " name read -p "请输入你的年龄: " age echo name=$name echo age=$age [root@shell /server/scripts ] # sh test.sh 请输入你的姓名: hehe # 书写 请输入你的年龄: 1 # 书写 name=hehe # 显示 age=1 # 显示 |
read第二种书写方式:一起
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@shell /server/scripts ] # cat test.sh #!/bin/bash read -p "请输入你的姓名和年龄: " name age echo name=$name echo age=$age [root@shell /server/scripts ] # sh test.sh 请输入你的姓名和年龄: nn 20 # 书写 name=nn # 显示 age=20 # 显示 [root@shell /server/scripts ] # cat test.sh #!/bin/bash read -p "输入要备份的目录: " dir tar zcf test . tar .gz $ dir [root@shell /server/scripts ] # sh test.sh 输入要备份的目录: /etc [root@shell /server/scripts ] # ll -rw-r--r-- 1 root root 86 Jul 20 20:23 test .sh -rw-r--r-- 1 root root 11571902 Jul 20 20:23 test . tar .gz |
13.小结
1.学习shell
2.基础知识
3.规范
4.语言种类
5.shell执行的三种方式
6.变量分类 export区别 变量相关的文件
7.变量的定义 名字定义 值的定义 命令的定义
8.核心位置变量 $0 $n $# $?
9.传参的三种方式 直接传参 赋值传参 read读入
——————————————————————————————————————————————————————————————————————————
无敌小马爱学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!