Shell脚本编程

目录

1.第一章 shell 概述

1.1为什么学习和使用Shell编程

1.2.shell是什么

Shell 概念

1.3.Shell 程序设计语言

1.3.1.shell 也是一种脚本语言

1.3.2.用途

1.4.如何学好shell

1.5shell脚本的基本元素

1.6shell脚本编写规范

1.6.1.脚本开头

1.6.2脚本中尽量不用中文注释

1.6.3.多使用内部命令

1.6.4没有必要使用cat命令

1.6.5.仔细阅读出错信息

1.6.6.文件名以sh结尾

1.6.7.代码缩进

1.7.shell脚本执行

1.7.1.方法1

1.7.2方法2

1.7.3方法3

1.7.4.方法4

1.7.5.注意:

1.8.bash shell基本功能

1.8.1.echo打印命令

1.8.2.printf命令

1.8.3.history历史命令

1.8.4.命令与文件名补全: tab

1.8.5.命令别名

1.8.6.命令执行顺序

1.8.7.管道符


Shell自动化运维编程基础

1.第一章 shell 概述

1.1为什么学习和使用Shell编程

        简单易学

        解释性语言,不需要编译即可执行

        对于一个合格的系统管理员来说,学习和掌握Shell编程是非常重要的,通过shell程序,可以在很大程度上简化日常的维护工作,使得管理员从简单的重复劳动中解脱出来]

1.2.shell是什么

1.2.1.shell起源

        1964年,美国AT&T公司的贝尔实验室、麻省理工学院及美国通用电气公司共同参与开始研发-套可以安装在大型主机上的多用户、多任务的操作系统,该操作系统的名称为Multics.1970年,丹尼斯·里奇和汤普逊启动了另外一个新的多用户、多任务的操作系统的项目,他们把这个项目称之为UNICS

        1973年,使用C语言重写编写了Unix。通过这次编写,使得Unix得以移植到其他的小型机上
面。。1979年,第一个重要的标准UNIX Shell在Unix的第7版中推出,并以作者史蒂夫·伯恩(StephenBourne) 的名字命名,叫做Bourne Shell,简称为sh。

        20世纪70年代末,cShell作为2BSD UNIX的一部分发布,简称csh。之后又出现了许多其他的Shell程序,主要包括Tenex C Shell (tcsh)、Korn Shell (ksh) 以及GNU Bourne-Againshell (bash)。Shell脚本编程_第1张图片

查看当前Linux系统当前支持的shell 

[root@server ~]# cat /etc/shells 
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
注意:/bin/bash和/usr/bin/bash其实是相同的,原因是Linux系统习惯将文件安装在/usr/bin下,为防止系统出问题,因此将其进行了备份

查看当前系统默认shell

[root@server ~]#  echo $SHELL
/bin/bash                                                #  注意   $  :意思为提取变量的值

Shell 概念

        Shell (外壳):是一种命令解释器程序,它能识别用户输入的各种命令,并传递给操作系统最大的作用是对命令进行语法检查。

        本质:是桥梁,将操作人员与计算机内核进行链接

        扩展:红帽扩展包 较好用 :epel

        RedHat9扩展包:https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

结构图:

Shell脚本编程_第2张图片

1.3.Shell 程序设计语言

1.3.1.shell 也是一种脚本语言

        任何代码最终都要被”翻译”成二进制的形式才能在计算机中执行

        有的编程语言,如 C/C++、Pascal、Go语言、汇编等,必须在程序运行之前将所有代码都翻译成二进制形式,也就是生成可执行文件,用户拿到的是最终生成的可执行文件,看不到源码。这个过程叫做编译(Compile),这样的编程语言叫做编译型语言,完成编译过程的软件叫做编译器(Compiler)。

        有的编程语言,如 Shell、JavaScript、Python、PHP等,需要一边执行一边翻译,不会生成任何可执行文件,用户必须拿到源码才能运行程序。程序运行后会即时翻译,翻译完一部分执行一部分,不用等到所有代码都翻译完。这个过程叫做解释,这样的编程语言叫做解释型语言或者脚本语言 (Script),完成解释过程的软件叫做解释器

        编译型语言的优点是执行速度快、对硬件要求低]保密性好,适合开发操作系统、大型应用程序、数据库等

        脚本语言的优点是使用灵活、部署容易、跨平台性好,非常适合 Web 开发以及小工具的制作。Shell 就是一种脚本语言,我们编写完源码后不用编译,直接运行源码即可

1.3.2.用途

        shell脚本的优势在于处理操作系统底层的业务 (linux系统内部的应用都是shell脚本完成)因为有大量的linux系统命令为它做支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。例如: 一键软件安装、优化、监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则。

        PHP、Python优势在于开发运维工具以及web界面的管理工具,web业务的开发等。处理一键软件安装、优化,报警脚本。常规业务的应用等php/python也是能够做到的。但是开发效率和复杂比用shell就差很多了。

1.4.如何学好shell

1.4.1熟练掌握shell编程基础知识

熟练使用vi(vim)编辑器

熟练掌握Linux基本命令

熟练掌握文本三剑客工具 (grep、sed、awk)

熟悉常用服务器部署、优化、日志及排错

1.4.2.建议

掌握Shell脚本基本语法

形成自己的脚本开发风格

从简单做起,简单判断,简单循环。

多模仿,多参考资料练习,多思考。

学会分析问题,逐渐形成编程思维。

编程变量名字要规范,采用驼峰语法表示。

不要拿来主义,特别是新手

1.5shell脚本的基本元素

1.5.1基本元素构成

        第1行的“#!/bin/bash"           (声明脚本的命令解释器)

        注释:说明某些代码的功能                  

        可执行语句:实现程序的功能

1.5.2shell脚本中的注释和风格

        作用:通过在代码中增加注释可以提高程序的可读性

        传统的Shell只支持单行注释,其表示方法是一个井号“#”,从该符号开始一直到行尾都属于注释的内容,如:
#comment1
#comment2
#comment3
..

        多行注释:使用冒号”.”配合here document,语法如下.
:<<'标志例如:1234'
comment1
comment2
comment3
·······
1234                             标志结尾
xxxx 可以是字符或数字,单引号可以不加,但以防出现莫名其妙的意外发生,lrn展,命令替换

1.6shell脚本编写规范

1.6.1.脚本开头

开头指定脚本解释器: #!/bin/sh 或 #!/bin/bash

其他行#表示注释0

程序段开头需要加版本版权等信息,如:

        1 # Date:创建日期
        2 # Author:作者
        3 # Mai:联系方式
        4 # Function:功能
        5 # Version:版本

 如何快速生成脚本开头的版本版权注释信息

 [root@server ~]# vim  ~/.vimrc 

autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"

func SetTitle()
        if expand("%:e") == 'sh'
                call setline(1,"#!/bin/bash")
                call setline(2,"##############################################################")
                call setline(3, "# File Name: ".expand("%"))
                call setline(4, "# Version: V1.0")
                call setline(5, "# Author: laoshi")
                call setline(6, "# Email: [email protected]")
                call setline(7, "# Organization: http://www.xx.com/xx/")
                call setline(8, "# Created Time : ".strftime("%F %T"))
                call setline(9, "# Description:")
                call setline(10,"##############################################################")
                call setline(11, "")
        endif
endfunc

结果: [root@server ~]# vim a.sh

Shell脚本编程_第3张图片

例:创建一个标准的脚本,实现有注释信息,版权信息,内容任意,并执行

实现结果数字屏幕:

[root@server ~]# vim cmatrix.sh

wget http://archive.ubuntu.com/ubuntu/pool/universe/c/cmatrix/cmatrix_1.2a.orig.tar.gz

tar xvf cmatrix_1.2a.orig.tar.gz

cd cmatrix-1.2a

yum install -y ncurses-devel

yum install -y gcc

./configure && make && make install

echo "Program installation complete!"
echo "Program installation complete!"
echo "Program installation complete!"

[root@server ~]# bash cmatrix.sh   # 执行cmatrix.sh

[root@server ~]# cmatrix   # 在解释器的任何位置输入,都会出现以下画面。

Shell脚本编程_第4张图片

1.6.2脚本中尽量不用中文注释

        别吝啬添加注释,必要的注释方便自己别人理解脚本逻辑和功能

        尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰

        单行注释,可以放在代码行的尾部或代码行的上部

        多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分 代码修改时,对修改的内容

1.6.3.多使用内部命令

        无论碰到哪种情况,请尽量考虑使用内部命令而不是外部命令

        内部命令执行的效率高,性能好

1.6.4没有必要使用cat命令

        这是我们经常在论坛里讨论的话题之一。没有必要使用cat命令指的是在有些时候,我们会发现根本没有必要使用cat命令。使用了多余的cat命令会让你的代码看起来很丑陋,而且还会带来性能上的问题

        例如:以下两条命令的结果一样

[root@server ~]# grep  root /etc/passwd
[root@server ~]# cat /etc/passwd | grep root

Shell脚本编程_第5张图片

1.6.5.仔细阅读出错信息

        程序员常犯的一个错误是:当我们敲入的命令报错后,我们中的大多数人只是对错误信息一瞥而过,而不会去认真的读一读,很多时候,错误信息里就包含了解决办法

        有时候我们修改了某个错误并再次运行后,系统依旧会报错。然后我们再次修改,但系统再次报错。这可能会持续很长时间。但实际上,旧的错误可能已经被纠正,只是由于出现了其它一些新错误才导致系统再次报错。而我们依旧在怀疑为什么修改好的代码依然不能正常运行。

        因此,请你养成仔细阅读错误信息的习惯。

1.6.6.文件名以sh结尾

        shell脚本文件名应见名知义,扩展名位sh,如: backup_mysql.sh

1.6.7.代码缩进

        shell没有强制要求,但建议缩进,这样可以提高阅读性,程序更有层次感

例:编写九九乘法表

[root@server ~]# vim 99.sh

# 命令解释器
for((i=1;i<10;i++))
do
        echo    -ne     "$i\t"     # 表头
done

echo

for((i=1;i<70;i++))
do
        echo    -n      "="        # 分割线
done

echo    

for((i=1;i<10;i++))    
do
        for((j=1;j<=i;j++))        # 行号i,列号j,j>=i打印右上半角;i>=j打印左下半角
        do
                echo    -en     "$i*$j=$[i*j]\t"
        done
        echo
done

        [root@server ~]# bash 99.sh 

Shell脚本编程_第6张图片

1.7.shell脚本执行

1.7.1.方法1

        使用sh或bash命令执行脚本,不需要执行权限(建议使用),脚本中可以不指定解释器

本质:脚本名当作参数传递给脚本解释器

[root@server ~]# vim   test.sh
#!/bin/bash
echo "china"
[root@server ~]# bash  Ttest.sh
china

[root@server ~]# bash   test.sh
china

        可以使用bash -n 脚本名,进行语法检测,且不执行脚本
        可以使用bash -x脚本名,进行脚本执行跟踪,逐条语句的跟踪执行.

1.7.2方法2

        切换到脚本所在目录使用./执行脚本,需要执行权限
[root@server ~]# ./telt.sh1
-bash: ./test.sh: 权限不够
[root@server ~]# chmod +x test.sh       # 还可以写为  chmod o+x test.sh

[root@server ~]# ./test.sh

1.7.3方法3

绝对路径执行脚本,需要执行权限

[root@server ~]# vim /tl.sh12

#!/bin/bash
echo "china"

[root@server ~]# /t1.sh                

-bash: /tl.sh: 权限不够

[root@server ~]# chmod  +x   /t1.sh

[root@server ~]# /t1.sh
china

例如:

[root@server ~]# /root/99.sh 
Shell脚本编程_第7张图片

1.7.4.方法4

使用点(  .   )或者source 执行脚本,不需要执行权限

[root@server ~]# source        /t1.sh                  # 本质是刷新脚本配置,副作用为执行脚本文件
china

[root@server ~]#   .  test.sh                                # .  是sorce的别名

china

1.7.5.注意:

        法1、2、3(bash、相对路径、绝对路径)都是启动一个子shell,在子shell中执行此脚本,脚本中设置的变量在脚本执行完毕后不会保存,执行完后返回主进程

        法4 都是在当前shell进程中执行此脚本,而不是重新启动一个shell 在子shell进程中执行此脚本,并且脚本中设置的变量在脚本执行完毕后会保存下来

优点:方法1、2、3 可以避免变量名重复

1.8.bash shell基本功能

1.8.1.echo打印命令

格式:echo        -参数         内容
参数:

        -n:取消输出后行末的换行符号
        -e:启用转义字符
可以输出带颜色的字体

格式:echo         -e        "\e[字体控制;字体颜色或背景色 字符串内容 \e[0m"
        \e[   表示控制开始,

        \e[0m   表示控制结束
字体控制选项: 1表示高亮,4表示下划线,5颜色闪烁
颜色如下:  字颜色:30-37,背景色: 40-47o

文字颜色:

        30m=黑色,31m=红色,32m=绿色,33m=黄色,34m=蓝色,35m=洋红,36m=青色,37m=白色。

字体背景色:

40m=黑色,41m=红色,42m=绿色,43m=黄色,44m=蓝色,45m=洋红,46m=青色,47m=白色。

1.8.2.printf命令

        printf 命令模仿C程序库 (library) 里的 printf()程序,由POSIX标准所定义,因此使用printf 的脚本比使用echo 移植性好,printf 使用引用文本或空格分隔的参数,外面可以在printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认 printf 不会像echo自动添加换行符,我们可以手动添加\n                        

格式:  

        print("格式空控制",内容)

       printf         格式控制宇符串        参数列表

        printf "%-10s %-8s %-4s\n"   姓名 性别 体重kg  
        printf "%-10s %-8s %-4.1f\n" 郭靖 男 66.1234 
        printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
        printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

执行脚本,输出结果如下所示:
姓名     性别   体重kg
郭靖     男      66.1
杨过     男      48.65
郭芙     女      47.99

        %s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。

        %-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。

        %-4.2f 指格式化为小数,其中 .2 指保留2位小数。

实例

# 单引号与双引号效果一样* 

        printf "%d %s\n" 1 "abc"
        printf '%d %s\n' 1 "abc" 
# 没有引号也可以输出
        printf %s abcdef
# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
        printf %s abc def
        printf "%s\n" abc def
        printf "%s %s %s\n" a b c d e f g h i j

# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替*
        printf "%s and %d \n"  

执行文件显示结果:
1 abc
1 abc
abcdefabcdefab c de
f g h
i j 
 and 0 

1.8.3.history历史命令

格式:

        history         [参数]         [历史命令保存文件]

参数:
        -c:清空历史命令记录    histtory -c 不带走一片云彩
        -w:把缓存中的历史命令写入历史命令保存文件。如果不手工指定历史命令保存文件,则放入默认历史命令保存文件~/.bash_history 中

修改默认记录历史命令条数:
        [root@server ~]# vim /etc/profile   # 定位四十九行;
        HISTSIZE=1000    # 含义用于控制历史条目数的默认存储1000条

面试题:显示history历史命令出现次数最高的top10

[root@server ~]# history |tr -s " " |cut -d " " -f 3 |sort | uniq -c | sort  -nr | head -10

 命令解析:历史命令|压缩空格| 列项截取第三列|排序|去重 |以第一列为依据降序|截取前十行                           
Shell脚本编程_第8张图片

面试题: 增加history显示的信息,如: 历史命令的执行时间

[root@server ~]#  vim ~/.bashrc             #  定位最后一行输入:

  export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S: "

Shell脚本编程_第9张图片
[root@server ~]# source ~/.bashrc      # 刷新配置使其生效
[root@server ~]# history 

Shell脚本编程_第10张图片

1.8.4.命令与文件名补全: tab

1.8.5.命令别名

格式:   alias   别名=原命令

例:
 [root@server ~]# alias hi=history
 [root@server ~]# hi

 [root@server ~]# which   hi  # 查看命令hi指向谁

注意:别名的优先级比命令高,命令执行时的顺序如下
        第一顺位:执行用绝对路径或相对路径执行的命令
        第二顺位:执行别名。
        第三顺位:执行 Bash 的内部命令。
        第四顺位: 执行按照 SPATH 环境变量定义的目录查找顺序找到的第一个命令

为了让这个别名永久生效,可以把别名写入环境变量配置文件”~/.bashrc”
[root@server ~]# cat  ~/.bashrc # 在最下面增加

[root@server ~]# source ~/.bashrc      # 刷新配置使其生效

3.4常用的别名

untar:
        由于 tar 命令的参数太多不好记忆,所以将解压缩设为如下
        alias untar='tar -zxvf
wget:
        下载大文件时的断点续连,防止网络异常中断:
        alias wget='wget -d
getpass:
        生成20个字符的随机数密码,使用 openssl 命令,但命令又很长不方便,可以设置别名
        alias getpass="openss] rand -base64 20'
ping:
        ping url时会无限次输出,但其实没多大意义,可以使用 -C 命令将其限制为 5次输出
        alias ping='ping -c 5

speed:
        测试网速命令speedtest-cli,为了方便使用可以设置别名

        安装:speedtest-cli是基于python编写的需要使用pip工具下载
[root@server ~]#
pip install  speedtest-cli                # 安装speedtest-cli  

bash: pip: command not found...

Instal] package 'python3-pip'lto provide command 'pip'? [N/y] y
*Waiting in queue...
*Loading ]ist of packages....&

The following packages have to be installed:
python3-pip-21.2.3-6.e19.noarchA tool for installing and managing9Python3 packages10

Proceed with changes? [N/y] y

[root@server ~]# speedtest-cli --list                # 查看当前可以测速的网络节点
Retrieving speedtest.net configuration...
24447) China Unicom 5G (Shanghai, China) [5.20 km]
30852) Duke Kunshan University (Kunshan, China) [49.69 km]
45170) China Unicom (Wu Xi, China) [113.94 km]
 5317) 江苏电信5G (Yangzhou, China) [233.26 km]
26352) China Telecom JiangSu 5G (Nanjing, China) [271.74 km]
56354) Unicom (Fuzhou, China) [612.14 km]
35722) 天津电信 (TianJin, China) [947.20 km]
34115) China Telecom TianJin-5G (TianJin, China) [947.20 km]
60584) GuangZhou-5G (Guangzhou, China) [1212.46 km]
35527) China Broadcasting Network Group Sichuan (Chengdu, China) [1659.93 km]

[root@server ~]# 
[root@server ~]# speedtest-cli --server 24447  --share                24447:节点号

Retrieving speedtest.net configuration...
Testing from China Unicom (123.138.132.78)...
Retrieving speedtest.net server list...
Retrieving information for the selected server...
Hosted by China Unicom 5G (Shanghai) [5.20 km]: 75.985 ms
Testing download speed................................................................................
Download: 70.01 Mbit/s                                #  长传速度为 70.01 Mbit/s 
Testing upload speed......................................................................................................
Upload: 33.65 Mbit/s                                     # 下载速度为 33.65 Mbit/s 
Share results: http://www.speedtest.net/result/15571757728.png  

                       #  该网址会将内容套入一个模板中,以后以图片形式展示

Shell脚本编程_第11张图片

1.8.6.命令执行顺序

顺序执行: ;
        [root@server ~]# date ; ls -1 /etc/passwd
并且:前面命令执行不成功,后面的命令不执行,前面命令执行成功,后面的命令执行: &&
        [root@server ~]# mkdir /mnt/iso && mount /dev/sr0 /mnt/iso、

                        # 左不成立右不执行

或者:前面命令成功,后面就不执行,前面不成功,后面就执行:  || 
        [root@server ~]# mkdir     tt   ||   ls   /
        [root@server ~]# mkdir     tt   ||   ls    / # 可以再次执行      

                        # 左不成立右执行  

1.8.7.管道符

        符号:  |  ,当在两个命令之间设置管道时,管道符|左边命令的输出就变成了右边命令的输入。只要第一个命令向标准输出写入,而第二个命令是从标准输入读取,那么这两个命令就可以形成一个管道

面试题:获取服务器的IP7地址(将本地或远程服务器的地址抓取并进行二次处理)

[root@server ~]# ip a | grep ens160 | grep inet | tr -s " " |cut -d " " -f 3
192.168.17.128/24

不包含子网掩码:

[root@server ~]# ip a | grep ens160 | grep inet | tr -s " " |cut -d " " -f 3 | cut -d "/" -f1
192.168.17.128

[root@server ~]# ip a | grep ens160 | grep inet | tr -s " " | tr -s "/" " " | cut -d " " -f 3
192.168.17.128

面试题:显示内存使用容量百分比

[root@server ~]# df -h | grep -w / | tr -s " " | cut -d " " -f5 
33%

面试题:显示内存的剩余容量

[root@server ~]# free -h |grep Mem |tr -s " " |cut -d " " -f4
671Mi

1.8.8.exit退出程序

作用:终止Shell程序的执行

格式:        exit         状态码

状态码:该参数是一个整数值,其取值范围为0~255
注意:Shell程序的退出状态码储存在系统变量S?中,因此,用户可以通过该变量取得Shell程序返回给父进程的退出状态码
常见状态码:
        0----------------命令运行成功
        1----------------通知未知错误
        2----------------误用she11命今
        126-------------命令不可执行
        127-------------没有找到命令
        128-------------无效退出参数
        128+X-----------Tinux信号x的严重错误
        130--------------命今通过Ctr]+C终止255--------------退出状态码越界
演示在不同的情况下,程序返回不同的状态码

查看上一条命令的返回状态码

[root@server ~]# echo $?      #shell中上一条命令的返回状态存储在变量 ?中 
0        

Shell脚本编程_第12张图片

你可能感兴趣的:(linux,运维,服务器)