专业做网站报价,安居客网官网入口,wordpress难度指数,北京网站设计制作#x1f49d;#x1f49d;#x1f49d;欢迎来到我的博客#xff0c;很高兴能够在这里和您见面#xff01;希望您在这里可以感受到一份轻松愉快的氛围#xff0c;不仅可以获得有趣的内容和知识#xff0c;也可以畅所欲言、分享您的想法和见解。
推荐:Linux运维老纪的首页…欢迎来到我的博客很高兴能够在这里和您见面希望您在这里可以感受到一份轻松愉快的氛围不仅可以获得有趣的内容和知识也可以畅所欲言、分享您的想法和见解。
推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老 导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。 常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等 数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂 非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。 ✨✨ 欢迎订阅本专栏 ✨✨
文章目录 1 Shell 基础介绍 1.1 Shell 简介 Shell 概述 Shell 发展史 查看Shell 查看系统默认安装的 Shell 查看当前登录用户默认 Shell 查看当前的 Shell 1.2 Shell 脚本(定义、作用、格式、权限及执行) Shell 脚本基础知识 Shell 脚本的约束Shell 脚本可以完成很多任务但不适用于所有情况 Shell 脚本开发环境 Shell 脚本指定解释器 执行 Shell 脚本 后台执行 Shell 脚本 2 Shell 编程基础 2.1 输入输出、管道 Linux 中的文本流 输出重定向 输入重定向 管道 2.2 字符、变量、运算 2.2.1 Shell 中的字符 2.2.2 Shell 中的变量 变量的类型 使用变量 扩展变量 变量的赋值和输出 2.2.3 Shell 的算术扩展 在 Shell 中计算时间 算术运算常用表达式 算术运算优先级 变量递增的前置后置区别 2.3 语句(条件、循环) Shell 中的结构化命令 条件语句 多分支判断语句 循环语句 for 循环 for 循环中的列表 for 循环奇数累加器 for 循环文件展示 while 循环 until 循环 使用循环打印乘法表 3 Shell 编程最佳实践 3.1 调试 Shell 脚本错误故障排除 调试模式 评估退出代码 3.2 语法风格 3.3 最佳实践示例 检测日志告警信息并邮件通知1 Shell 基础介绍 1.1 Shell 简介 Shell 概述 Shell 是系统的用户界面提供了用户与内核进行交互操作的一种接口 Shell 将用户输入的命令并且把它们送到内核去执行然后返回执行结果 Shell 是可编程的它允许用户编写由 Shell 命令组成的程序 Shell 发展史 1971 : Bell Labs 的 Ken Thompson 为 UNIX 开发了第一个 Shell: V6 Shell 是一个在内核之外执行的独立的用户程序 1977 Steven Bourne 在 ATT Bell Labs 为 V7 UNIX 创建 Bourne shell 1978 Bill Joy 在伯克利分校攻读研究生期间为 BSD UNIX 系统开发的 csh 1983 Ken Greer 在卡内基-梅隆大学开发了 tcsh将 C Shell 引入了 Tenex 系统中的一些功能如命令行编辑功能和文件名和命令自动补全功能 1983 David Korn 在 ATT Bell Labs 创建 korn shell它功能更强大提供关联数组表达式运算 1989 Bourne-Again Shell或 Bash是一个开源 GNU 项目旨在取代 Bourne shellBash 由 Brian Fox 开发已成为世上最流行的 Shell它兼容 sh、csh、ksh是 Linux 系统的默认 Shell 在 Linux 中有多种 Shell 程序可供选择比如 dash、csh、zsh 等默认的 Shell 可以在 /bin/sh 查看在etc/passwd 中修改。
查看Shell 查看系统默认安装的 Shell
cat /etc/shells
查看当前登录用户默认 Shell
echo $SHELL
查看当前的 Shell
echo $0
1.2 Shell 脚本(定义、作用、格式、权限及执行) Shell 脚本基础知识 在 Unix/Linux 里一个程序/命令只做好一件事复杂的问题可以通过多个命令的组合来解决形式最简单的 Shell 脚本就是一系列命令构成的可执行文件并可以被其他脚本复用。编写风格良好易读的 Shell 脚本可以提高日常任务的自动化程度和准确性。
Shell 脚本的约束Shell 脚本可以完成很多任务但不适用于所有情况 Shell 脚本可以完成很多任务但不适用于所有情况 对于可以通过调用其他命令行实用工具来完成的任务Shell 脚本是一种不错的选择 Shell 脚本可以作为一种“胶水”语言整合其他编程语言 当解决某个问题时Shell 脚本实现起来复杂度高效率低此时就可以考虑使用其他编程语言。 Shell 脚本开发环境 可以在任意文本编辑器中打开新文件来创建 Shell 脚本。
高级编辑器如 Vim 和 Emacs在识别文件的后缀为 .sh 后可以提供语法高亮、检查、补全等功能。
[rootlocalhost~]# vim demo.sh #新建一个脚本文件并写入如下内容
#!/bin/bash
echo Hello World“
[rootlocalhost~]# sh demo.sh
Hello WorldShell 脚本指定解释器 Shell 脚本只是静态的代码若要输出结果还需要解释器的参与。一般在脚本的第一行指定执行此脚本的解释器。如果不指定解释器脚本也能在默认的解释器中正常运行但出于规范和安全的考虑建议指定如下
#!/bin/bash#!/bin/csh
执行 Shell 脚本 对于脚本文件我们有两种执行方式
sh script_name.sh
./script_name.sh
Linux 中一切皆文件脚本/命令/程序都是一个文件文件作为一个对象具有权限的属性。在执行别人发送或从网上下载的脚本时可能会遇到权限问题赋予执行权限可解决
chmod x script_name.sh
如果某个 Shell 脚本可执行则可以通过在命令行中输入其名称调用.被成功调用的前提是脚本所在路径包含在 $PATH 变量中
查看 $PATH 变量 修改 $PATH 变量 查找某个命令/脚本的路径
[rootlocalhost~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[rootlocalhost~]# PATH$PATH:/New/path
[rootlocalhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/New/path
#永久修改 $PATH 需要在 .bashrc 或 .bash_profile 中添加 export PATH“$$PATH:/new/path”
后台执行 Shell 脚本 有时候一些脚本执行时间较长命令行界面会被占用因此可以采取后台运行脚本 ./my_script.sh
这种方法在退出 Shell 后脚本进程会随之终止为了保证脚本一直运行可以采用 nohup ./my_script.sh
脚本的的标准输出和标准错误会重定向到 nohup.out 文件里
使用 jobs 命令可以查看后台中运行着的进程。
2 Shell 编程基础2.1 输入输出、管道 Linux 中的文本流 文本流存在于 Linux 的每一个进程中。Linux 的每个进程启动时会打开三个文本流的端口标准输入、标准输出、标准错误。这三个端口对应着一个程序的输入、输出和异常的抛出。
例如 在 bash 中输入一串字符后bash 进程中的标准输入端口捕获命令行中的输入进行处理后从标准输出端口中传出回显在屏幕上如果处理过程中发生异常则会通过标准错误端口将异常回显在屏幕上。
输出重定向 某些情况下我们需要保存程序的输出此时就可以通过重定向将程序的输出保存到文件中
将标准输出定向到文件中, 使用这种方式会将程序的标准输出覆盖文件内容 ls dir_log
将标准输出追加到文件中, 使用这种方式会将程序的标准输出追加至文件的末尾 ls dir_log
执行完命令后可以通过 cat dir_log 查看保存的文件内容输入重定向 与输出重定向类似输入重定向是把程序的标准输入进行重新定向。
输入重定向
格式command inputfile 将右边的文件作为标准输入然后传入左边的命令 例 wc -l /dev/null 内联输入重定向
格式 command maker 输出重定向需要文件而内联输入重定向可以使用即时输入的文本作为标准输入传入左边的命令 右边的字符“maker”作为标志表示标准输入的开始和结束自身不包含在标准输入里。 下图例中以“maker”作为标志
command maker file同时将输入的内容存成文件
管道 有时需要将一个命令的输出连到另一个命令的输入如果用重定向实现会较复杂。
管道( | )就像现实中的水管一样可以连接两个命令的输入和输出甚至是串联多个命令
格式command1 | command2 | command3
[rootlocalhost ~]# ls /bin/ | grep python | less
管道实际上是进程间通信IPC的一种方式
2.2 字符、变量、运算 2.2.1 Shell 中的字符 和其他编程语言一样Shell 也有一些保留字特殊字符在编写脚本时需要注意。
注释符号(Hashmark[Comments]) 在shell文件的行首作为shebang标记#!/bin/bash; 其他地方作为注释使用在一行中#后面的内容并不会被执行除非用单/双引号包围时#作为#号字符本身不具有注释作用。 单引号(full quoting [single quote]) 单引号括住的内容被视为单一字符串引号内的禁止变量扩展所有字符均作为字符本身处理除单引号本身之外单引号必须成对出现。 反斜线反斜杆(escape [backslash]) 放在特殊符号之前转义特殊符号的作用仅表示特殊符号本身这在字符串中常用放在一行指令的最末端表示紧接着的回车无效其实也就是转义了Enter后继新行的输入仍然作为当前指令的一部分。 斜线斜杆Filename path separator [forward slash] 作为路径的分隔符路径中仅有一个斜杆表示根目录以斜杆开头的路径表示从根目录开始的路径 在作为运算符的时候表示除法符号。如a4/2 感叹号reverse (or negate) [bang],[exclamation mark]) 取反一个测试结果或退出状态。表示反逻辑比如后面的!,这个是表示不等于表示取反如ls a[!0-9] 表示a后面不是紧接一个数字的文件 2.2.2 Shell 中的变量 任何语言都有变量这个要素。Shell 与其他强类型的编程语言如CJava 和 C 等有很大不同Shell 中的变量是无类型的。通过一个变量我们可以引用一块内存区域的值变量名就是这块内存区域上贴的一个标签。
变量赋值variablevalue
变量的类型 在 Linux Shell 中变量主要有两大类环境变量和用户定义变量。每种类型的变量依据作用域不同又分为全局变量和局部变量
全局变量作用在整个 Shell 会话及其子 Shell 局部变量作用在定义它们的进程及其子进程内查看变量
使用 printenv 查看全局变量 使用 set 查看某个特定进程中的所有变量包括局部变量、全局变量以及用户定义变量 对比 printenv 与 set 的区别dif -yw (printenv) (set) 命令set是Shell中的一个内建命令它能够显示当前Shell中的变量已经用户自定义的变量不管该变量有没有export。set命令允许你更改Shell选项的值并设置位置参数或者显示Shell变量的名称和值。如果未提供任何选项或参数则会设置显示所有Shell变量和函数的名称和值按照当前语言环境排序并且输出的格式可以重新用作设置或重置当前设置变量的输入 printenv和env在环境变量打印方面是类似的。但是在功能上env主要用于设置环境变量并运行指定的命令命令而printenv是为了打印环境变量。 set则是一个Shell的内建命令与Shell有关用于设置Shell的属性。
修改变量
在 .bash_profile 或 .bashrc 中添加 export 语句永久修改变量 使用变量 Shell 变量命名规则
变量名由数字、字母、下划线组成 必须以字母或者下划线开头 不能使用 Shell 里的关键字 定义变量的格式
variablevalue
variablevalue
variablevalue
赋值号的周围不能有空格 如果有必要也可以使用 declare 关键字显式定义变量的类型 查询关键字help | grep keywords 如果 value 包含了空白符则需要用引号包裹起来 单引号包裹的内容shell 不展开命令、变量即原样输出 双引号反之会展开其中包裹的命令和变量 扩展变量 在以下示例中如果不使用花括号Bash 会将$FIRST_$LAST 解释为变量 $FIRST_ 后跟变量 $LAST而不是由_ 字符分隔的变量 $FIRST 和 $LAST。
因此在此情况下必须使用花括号引用的形式才能使变量扩展正确运行。
变量的赋值和输出 定义并赋值如下变量个人姓名 name日期 time 输出姓名及日期变量 读取输入并输出。read 命令等待用户输入随后将输入的内容赋给变量
2.2.3 Shell 的算术扩展 算术扩展可用于执行简单的整数算术运算 语法$[表达式] 如
[rootlocalhost ~]# echo $[19]
10
[rootlocalhost ~]# echo $[8*8]
64
[rootlocalhost ~]# count1;echo $[$[$count3]*2]
8
在 Shell 中计算时间 定义24小时60分钟60秒变量定义每天秒数变量并赋值输出变量
[rootlocalhost ~]# SEC_PER_MIN60
[rootlocalhost ~]# MIN_PER_HR60
[rootlocalhost ~]# HR_PER_DAY24
[rootlocalhost ~]# SEC_PER_DAY$[$SEC_PER_MIN*$MIN_PER_HR*$HR_PER_DAY]
[rootlocalhost ~]# echo There are $SEC_PER_DAY seconds in a day
There are 86400 seconds in a day
算术运算常用表达式算术运算优先级 优先级由高到低如下
变量递增的前置后置区别 i 要开辟一个变量来保存 i 的值 并返回然后让 i 这个变量 的值 1 。而 i 直接把 1 加到 i 这个 变量的空间中去并返回这个空间 中的值 没有开辟任何临时空间性能更高。
2.3 语句(条件、循环) Shell 中的结构化命令 在 Shell 脚本里除了顺序执行还需要一些额外的逻辑控制流程。
和其他编程语言类似 Shell 中的结构化命令主要包括条件、循环两类
条件语句 Shell 中的 if 和其他 if 判断的条件不太一样需注意。
If-then 语句 语法
if commandthencommandsfiBash Shell 会先执行 if 后面的语句如果其退出状态码为 0则会继续执行 then 部分的命令否则会执行脚本中的下一个命令。
多分支判断语句 在涉及多条件判断时可能会使用较为繁琐的 if-then-else 语句通过 elif 语句频繁检测同一个变量的值此时更适合使用 case 语句 语法
case variable inpattern1 | pattern2) commands1;;pattern3) commands2;;*) default commands;;
esac
case 语句会将指定的变量与不同的模式比较若匹配则执行对应的命令 用 | 可以分割出多个模式 用 * 代表所有与已知模式不匹配的值循环语句 Shell 脚本中常会遇到一些重复任务相当于循环执行一组命令直到满足了某个特定条件
常见的循环语句有三种for、while、until
循环控制符有两种break、continue 用于控制循环流程的转向
for 循环
#Shell风格语法
for var in listdocommandsdone#例
for i in {1..10}
doprintf $i\n
done#c语言风格
for ((var assignment ; condition ; iteration process))
docommands
done#例
for (( i 1; i 10 ; i))
doecho “Hello”
done
do和done之间的命令称为循环体执行次数和list列表中常数或字符串的个数相同。for循环首先将in后list列表的第一个常数或字符串赋值给循环变量然后执行循环体以此执行list最后执行done命令后的命令序列。
for 循环中的列表
[rootlocalhost~]# for HOST in host1 host2 host3; do echo $HOST; done
host1
host2
host3
[rootlocalhost ~]# for HOST in host{1..3}; do echo $HOST; done
host1
host2
host3
[rootlocalhost~]# for EVEN in $(seq 2 2 8); do echo $EVEN; done;
for 循环奇数累加器 定义奇数累加器文件并执行 参考脚本
#!/bin/bashsum0
for i in {1..100..2}
dolet sumi
done
echo sum$sum
for 循环文件展示 展示目录下所有文件 参考脚本
#!/bin/bashfor file in $(ls)
doecho file: $file“
done
while 循环 也称为前测试循环语句重复次数是利用一个条件来控制是否继续重复执行这个语句。为避免死循环必须保证循环体中包含循环出口条件
#!/bin/bashsum0;i1
while(( i 100 ))
dolet sumilet i 2
doneecho sum$sumuntil 循环 与 while 循环类似但是跳出循环的条件判断有所区别
#!/bin/bash
#奇数累加器sum0;i1
until(( i 100 ))
dolet sumilet i 2
doneecho sum$sum
使用循环打印乘法表 参考脚本
#!/bin/bashfor (( i 1; i 9; i ))do for (( j1; j i; j ))do let temp i * j echo -n $i*$j$temp done
printf “\n”
done
3 Shell 编程最佳实践 3.1 调试 Shell 脚本错误故障排除 编写、使用或维护 Shell 脚本的管理员不可避免地会遇到脚本的错误
错误通常是由于输入错误、语法错误或脚本逻辑不佳导致 在编写脚本时,将文本编辑器与 bash 语法高亮显示结合使用可以帮助使错误更明显 找到并排除脚本中错误的最直接方法是调试 避免在脚本中引入错误的另一种简单方法是在创建脚本期间遵循良好风格 调试模式 脚本上激活调试模式,请向脚本第一行中的命令解释器中添加 -x 选项 如此前乘法表进行如下修改
#!/bin/bash -x
1
bash 的调试模式将打印出脚本执行前由脚本执行的命令,已执行的所有 shell 扩展的结果都将显示在打印输出中所有变量数据状态会实时打印以供跟踪bash -x adder.sh
1
评估退出代码
每个命令返回一个退出状态也通常称为返回状态或退出代码
退出代码可以用于脚本的调试
以下示例说明了几个常见命令的执行和退出状态检索
[rootlocalhost tmp]# ls /etc/hosts
/etc/hosts
[rootlocalhost tmp]# echo $?
0
----------------------------------------------------------------
[rootlocalhosttmp]# ls /etc/nofile
ls: cannot access /etc/nofile: No such file or directory
[rootlocalhost tmp]# echo $?
在脚本中使用退出代码 一旦执行脚本将在其处理所有内容之后退出但是有时候可能需要中途退出脚本比如在遇到错误条件时 可以通过在脚本中使用 exit 命令来实现这一目的当脚本遇到 exit 命令时脚本将立即退出并跳过对脚本其余内容的处理
[rootlocalhosttmp]# cat hello.sh
#!/bin/bash
echo Hello World
exit 1
[rootlocalhosttmp]# ./hello.sh
Hello World
[rootlocalhost tmp]# echo $?
3.2 语法风格 以下是要遵循的一些具体做法:
将长命令分解为多行更小的代码块代码段越短就越便于读者领悟和理解 将多个语句的开头和结尾排好以便于查看控制结构的开始和结束位置以及它们是否正确关闭 对包含多行语句的行进行缩进以表示代码逻辑的层次结构和控制结构的流程 使用行间距分隔命令块以阐明一个代码段何时结束以及另一个代码段何时开始 在整个脚本中通篇使用一致的格式 修改后的脚本
#!/bin/bash
# 此脚本是读取关于kernel相关的软件包信息并从RPM数据库中查询软件包的安装时间
PACKAGETYPEkernel
PACKAGES$(rpm -qa | grep $PACKAGETYPE)
# 循环处理信息
for PACKAGE in $PACKAGES; do #查询每个软件包的安装时间截INSTALLEPOCH$(rpm -q --qf %{INSTALLTIME}\n $PACKAGE)# 把时间截转换为普通的日期时间INSTALLDATETIME$(date -d $INSTALLEPOCH)# 打印信息echo $PACKAGE was installed on $INSTALLDATETIME
done
3.3 最佳实践示例 检测日志告警信息并邮件通知 场景描述 某运营商要求对当前环境日志文件“error.log”进行长期监测如发现关键词“danger”则发送告警邮件
要求
日志文件可自己新建用脚本模拟写入 发送邮件可通过 mail 指令但受限实验环境可通过向日志文件写入“mail”字符串来替代 运行监测脚本 日志初始内容为空写入关键词“danger” 自动发送邮件写入 mail 替代
#!/bin/bash
# 日志检测脚本 test.shtail -f /var/log/error.log | while read danger;
do echo ‘mail’ /var/log/error.log;
sleep 1m;
done#!/bin/bash
# 模拟报错脚本 addlog.shecho ‘danger’ /var/log/error.log
后台运行监测脚本
./test.sh
模拟报错
./addlog.sh
查看 error.log 文件检查结果
cat /var/log/error.log