目标:
1、了解编程基础概念
2、掌握shell的概述概述
3、掌握shell脚本的注意事项
4、掌握Bash基本功能
一、编程基础
1.1 什么是编程?
百度百科定义:编程是编定程序的中文简称,就是让计算机代码解决某个问题,对某个计算体系规定一定的运算方式,使计算体系按照该计算方式运行,并最终得到相应结果的过程。
为了使计算机能够理解人的意图,人类就必须将需解决的问题的思路、方法和手段通过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完成某种特定的任务。这种人和计算体系之间交流的过程就是编程。
1.2 程序的结构
程序:算法+数据结构
数据:是程序的核心
算法:处理数据的方式
数据结构:数据在计算机中的类型和组织方式
1.3 编程语言的分类
编程语言可以根据其设计目的、执行方式、语法和语义等多种因素进行分类。以下是一些常见的编程语言分类:
-
低级语言与高级语言
-
低级语言:包括机器语言和汇编语言。机器语言是计算机能直接理解和执行的语言,由二进制代码组成;汇编语言则是一种符号化的机器语言,使用助记符表示指令,但仍需要汇编器转换为机器语言才能执行。
-
高级语言:更接近于人类的自然语言,易于学习和使用。例如,C、C++、Java、Python、JavaScript等都是高级语言。高级语言编写的程序需要通过编译器或解释器转换为机器语言才能执行。
-
-
编译型语言与解释型语言
-
编译型语言:如C、C++、Java等,在程序运行前需要先通过编译器将源代码转换为可执行文件。编译后的程序执行速度较快,但编译过程需要一定时间。
-
解释型语言:如Python、Ruby、JavaScript等,在程序运行时通过解释器逐行读取源代码并转换为机器语言执行。解释型语言的优点是开发效率高,可以边开发边调试,但执行速度可能较慢。
-
-
过程式语言与面向对象语言
-
过程式语言:以函数或过程为中心,关注如何执行一系列操作,如C语言。
-
面向对象语言:将数据和操作封装在对象中,通过对象之间的交互实现程序功能。Java、C++、Python等都是面向对象的语言。面向对象语言有助于提高代码的可重用性和可维护性。
-
-
脚本语言与通用语言
-
脚本语言:通常用于自动化任务、系统管理和Web开发等领域,如Shell脚本、Perl、Python等。它们通常具有简单的语法和快速的开发周期。
-
通用语言:适用于各种应用领域的编程语言,如C、C++、Java等。它们具有强大的功能和广泛的应用场景。
-
这只是一些常见的分类方式,实际上编程语言的分类还可以根据其他因素进行细分,如并发编程语言、内存安全语言等。每种编程语言都有其独特的优缺点和适用场景,开发者可以根据项目需求和个人偏好选择合适的编程语言。
1.3.1 高级语言
1、编译型语言: 编译性语言写的程序在被执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。
有些程序编译后,还需要把其他编译好的,可能需要组装两个以上的目标代码生成最终的可执行性文件,称为链接(可实现对低层次代码的复用)。
2、解释型语言: 解释性语言的程序不需要编译,在运行程序的时候才翻译,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就需要逐行翻译一次,效率比较低。
现代解释性语言通常把源程序编译成中间代码,然后用解释器把中间代码一条条翻译成目标机器代码,一条条执行。比如Java,Java首先是通过编译器编译成字节码文.class,然后在运行时通过解释器给解释成机器文件。所以我们说Java是一种先编译后解释的语言。再比如C#,C#首先是通过编译器将C#文件编译成IL文件,然后在通过CLR将IL文件编译成机器文件。所以我们说C#是一门纯编译语言,但是C#是一门需要二次编译的语言。同理也可等效运用到基于.NET平台上的其他语言。
任何语言都必须翻译成机器语言,计算机才能运行高级语言编写的程序。 翻译的方式有两种:一个是编译,一个是解释
示例:
下面是一个C编写一个打印"Hello, World!"的程序。 C语言版本: #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; } 下面是一个Python编写一个打印"Hello, World!"的程序。 print("Hello, World!") 下面是一个使用Java编写的打印"Hello, World!"的程序: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } 注意: C语言的程序需要编译后才能运行,而Python的程序可以直接运行。在C语言中,我们使用printf函数来打印输出,而在Python中,我们使用print函数。两者都实现了同样的目标:在屏幕上打印出"Hello, World!"。
1.4 编程逻辑处理过程
编程逻辑的处理思路和过程,通常会涉及以下几个关键步骤:
-
问题分析
首先,明确问题的具体需求。这包括理解问题的背景、输入、输出以及限制条件。例如,你可能被要求编写一个程序来找出数组中的最大值,或者实现一个排序算法。
-
算法设计
基于问题分析,设计适当的算法来解决问题。这可能涉及选择或发明新的数据结构,以及确定算法的主要步骤和逻辑。例如,对于找出数组中的最大值,一个简单的算法是遍历数组并比较每个元素。
-
编写代码
使用选定的编程语言,将算法转换为具体的代码。这包括定义变量、函数和类(如果需要),以及实现算法的逻辑。注意代码的清晰性和可读性,以及遵循编程语言的最佳实践。
-
测试与调试
编写完代码后,进行测试以确保其正确性和性能。这包括单元测试(测试代码的各个部分)和集成测试(测试整个程序)。如果发现问题,需要进行调试,即找出并修复代码中的错误。
-
优化与改进
根据测试结果,对代码进行优化和改进。这可能涉及改进算法的效率、减少内存使用或提高代码的可维护性。优化是一个持续的过程,可以在后续的开发和维护中进行。
-
文档编写
为代码编写文档,解释其用途、输入、输出、参数以及任何重要的实现细节。这有助于其他人理解和使用你的代码
二、编写shell脚本
2.1 什么是shell?
shell是一个命令行的解释器,它为用户体提供了一个向LINUX内核发送请求以便于运行程序的界面系统级的应用,用户可以使用shell来启动,挂起,停止甚至是编写一些程序。同时shell还是一个功能相当强大的编程语言,易编写,易调试,灵活性较强,shell是解释执行的脚本语言,在shell中可以直接调用Linux的系统命令。
shell可以通过提示输入您输入,向操作系统解释该输入,然后来处理来自操作系统的任何结果的输出,简单来说,shell就是一个命令的解释器,用于将人的操作逻辑翻译成内核可以识别的操作。
2.2 shell和内核的位置关系
2.3 Shell分类和对比
shell类型 | 易学性 | 可移植性 | 编辑性 | 快捷性 |
---|---|---|---|---|
Bourne Shell(sh) | 容易 | 好 | 较差 | 较差 |
Korn Shell | 较难 | 较好 | 好 | 较好 |
Bourne Again(Bash) | 难 | 较好 | 好 | 好 |
POSIX shell(psh) | 较难 | 好 | 好 | 较好 |
C Shell | 较难 | 差 | 较好 | 较好 |
TC shell | 难 | 差 | 好 | 好 |
Bourne Shell:从1979年起Unix就开始使用Bourne Shell,Bourne Shell的主文件名为sh。
C Shell:C Shell主要在BSD版的Unix系统中使用,其语法和C语法相类似而得名。
Shell的两种主要语法类型有Bourne和C,这两种语法彼此不兼容。Borune家族主要包括sh、ksh、Bash、psh、zsh;C家族主要包括:csh、tcsh。
不同的shell语言的语法不同,一般是不能交换使用的,最常用的shell是bash,也就是Bourne Shell,Bourne Shell,bash由于易用和免费,在工作中被广泛的应用,也是大多数Linux操作系统默认的shell
2.4 查看当前系统的默认shell
[root@localhost ~]# echo $SHELL /bin/bash
2.5 查看系统支持的shell类型
[root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh [root@localhost ~]# chsh -s /bin/sh #切换shell,切换完了重新登录终端。 Changing shell for root. Shell changed.
2.6 shell脚本的功能
1、自动化批量系统初始化程序(系统更新,软件更新,时区设置) 2、 自动化部署软件(LNMP,LAMP等) 3、 自动化系统监控指标采集工具(CPU,memory,Disk等) 4、 自动数据库备份工具
一句话总结:将重复性、复杂化的工作通过编写脚本来一键式完成,如果遇到相同场景,一键执行脚本即可完成大量工作,减轻了工作的复杂度,提升效率。
2.7 shell脚本的命名规则
shel脚本编程需要注意以下几个事项:
1、shel脚本名称命名一般为英文的大写、小写; 2、不能使用特殊符号、空格来命名(!@#$); 3、shell脚本后缀以.sh结尾; 4、不建议shell命名为纯数字, 一般以脚本功能命名 5、shell脚本内容首行需以#!/bin/bash开头(shebang) 6、shell脚本中变量名称尽量使用大写字母, 字母间不能使用“-”, 可以使用“_”; 7、shell脚本变量名称不能以数字、特殊符号开头。
shell脚本编程:是基于过程式、解释执行的脚本语言,shell脚本简单来说就是把一堆命令写入一个文件,执行文件相当于执行一堆命令
编程语言的基本结构:
-
各种系统命令的组合
-
数据存储:变量、数组
-
表达式:a + b
-
控制语句:if
-
循环语句:while for
shell脚本:包含一些命令或脚本声明格式,并符合一定格式的文本文件
2.8 创建shell脚本过程
第一步:创建一个普通文本文件,为了表明是shell脚本,一般后缀为.sh
第二步:声明shell脚本使用的解释器类型
格式要求:首行shebang机制,也就是shell脚本的第一行必须声明bash解释器
#!/bin/bash 通过bash解释器执行脚本的声明 #!/use/bin/perl 通过perl语言编写的脚本声明 #!/use/bin/python 通过Python语言编写脚本声明
第三步:添加注释信息,声明脚本作用
第四步:编写命令,实现功能
第五步:给予脚本的可执行权限
第六步:执行脚本,通过运行shell解释器,将脚本文件当做参数传入执行。
2.9 第一个shell脚本
在执行之前,我们先写一个简单的shell脚本
#!/bin/bash # This is my First shell # By author teacher wu echo "Hello world"
first_shell.sh脚本内容详解如下:
1. #!/bin/bash:固定格式, 定义该脚本所使用的shell类型。 2. #This is my First shell:#号表示注释, 没有任何的意义, shell不会解析它。 3. #By author teacher wu:表示脚本创建人, #号表示注解。 4. echo“HelloWorld!” : shell脚本主命令, 执行该脚本呈现的内容, 5. shel脚本编写完毕, 如果运行该脚本, 运行用户需要有执行权限, 可以使用chmod o+x first_shell.sh赋予可执行权限。然后./first_she ll.sh执行即可
2.10 脚本的执行方式
# 方式一:sh <脚本名称> <参数> 例:[root@centos7 /script ]# sh script.sh # 方式二:bash <脚本名称> <参数> 例:[root@centos7 /script ]#bash script.sh # 方式三:. <路径>/<脚本名称> 例:[root@centos7 /script ]#. script.sh # 方式四:<绝对路径>/<脚本名称> <参数> 例:[root@centos7 /script ]#/home/test/script.sh # 方式五:soure <路径>/<脚本名称> 例:[root@centos7 /script ]#source script.sh # 方式六: cat 脚本名称|bash 例:[root@centos7 /script ]#cat script.sh|bash 方式七:配置PATH变量, 此方法不推荐 [root@centos7 /script ]# echo "PATH=.:$PATH" > /etc/profile.d/PATH.sh [root@centos7 /script ]# . /etc/profile.d/PATH.sh [root@centos7 /script ]# hello.sh
例如:
[root@localhost ~]# ./first_shell.sh Hello world
还可以直接使用命令执/bin/sh first_shell.sh直接运行脚本, 不需要执行权限, 最终脚本执行显示效果一样
[root@localhost ~]# /bin/sh first_shell.sh Hello world
范例:
#!/bin/bash #Description: The test script #QQ: 452495750 #Author: test #email: testainio@qq.com #FileName: first.sh #Date: 2022-08-11 #======================================================= echo "My hostname is `hostname`" echo "This is time `date +'%F %T'`"
[root@localhost shells]# chmod a+x first.sh ##添加执行权限 [root@localhost shells]# bash first.sh ##执行脚本 My hostname is localhost.localdomain This is time 2022-08-11 11:16:48
vim自动生成注释
[root@centos7 ~ ]# vim ~/.vimrc set number set ignorecase set cursorline set autoindent set et set ts=4 inoremap ( ()<ESC>i inoremap [ []<ESC>i inoremap { {}<ESC>i inoremap < <><ESC>i inoremap ' ''<ESC>i inoremap " ""<ESC>i autocmd BufNewFile *.sh exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2,"#********************************************************************") call setline(3,"#Name: test") call setline(4,"#Date: ".strftime("%Y-%m-%d")) call setline(5,"#FileName: ".expand("%")) call setline(6,"#Description: The test script") call setline(7,"#********************************************************************") call setline(8,"") endif endfunc autocmd BufNewFile * normal G
2.11 脚本调试
脚本调试可以发现一些隐藏的脚本语法或者逻辑问题,可以快速的帮我们定位和发现问题,提高效率
2.11.1 检查语法问题
调试不执行
bash [options] 选项: -n:不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示。 -v:在执行脚本时,先将脚本的内容输出到屏幕上,然后执行脚本,如果有错误,也会给错误提示。 -x:将执行的脚本内容及输出显示到屏幕上。
2.11.2 检查逻辑问题
调试执行
bash -x script_filename ##检查逻辑问题
范例:
[root@akesu shells]# cat test1.sh ##脚本模板 #!/bin/bash echo aaa cat >a.txt <<EOF ABC AB ABC EOF [root@akesu shells]# bash -n test1.sh test1.sh: line 15: warning: here-document at line 10 delimited by end-of-file (wanted `EOF') ##可以看到在第15行发现有问题,我故意在EOF后加了一个空格,去掉空格就行。
范例:
[root@akesu shells]# bash -x test1.sh + echo aaa ##一步一步执行,看结果是否正确 aaa test1.sh: line 15: warning: here-document at line 10 delimited by end-of-file (wanted `EOF') + cat
总结:脚本中常见的错误有三种:
1)逻辑问题:可以使用bash -x 进行调试查看 2)语法问题:可以使用bash -n进行调试,但是后续命令不在执行 3) 脚本内部命令错误:后续命令还会执行,用bash -n无法检测,只能使用bash-x进行检测
2.12 脚本的注释
在Shell脚本中,可以使用注释来提供对代码的解释和说明。Shell脚本支持两种注释语法:单行注释和多行注释。
2.12.1 单行注释
在Shell脚本中,使用#
符号表示单行注释。#
符号后面的内容将被视为注释,不会被执行。
示例:
#!/bin/bash # 这是一个单行注释 echo \"Hello, World!\" # 这也是一个单行注释
输出:
Hello, World!
在上面的示例中,我们使用#
符号创建了两个单行注释。这些注释不会被执行,只是提供了对代码的解释。
2.12.2 多行注释
在Shell脚本中,可以使用以下语法创建多行注释:
: <<EOF 这是一个多行注释。 这里可以写多行注释的内容。 EOF
示例:
#!/bin/bash :<<EOF 这是一个多行注释的示例。 这里可以写多行注释的内容。 ' EOF echo \"Hello, World!\"
输出:
Hello, World!
三、Bash基本功能
3.1 echo命令
语法:echo [选项] [输出内容]
选项:
-e: 支持反斜线控制的字符转换 -n: 取消输出后末行的换行符号
范例1:
[root@localhost ~]# echo "hello shell" hello shell
范例2:
[root@localhost ~]# echo -n "hello shell" hello shell[root@localhost ~]#
echo如果使用了“e”,则可以控制字符:
\a 警示字符 \b 退格 \c 忽略输出中最后的换行符号。这个参数之后的任何字符,包括后面的参数都会被忽略掉。 \f 自动换行,新行接上一行尾部 \n 换行 \r 回车 \t 水平制表符号 \v 垂直制表符号
范例3:制表符
[root@localhost ~]# echo -e "\ta\tb\te" a b e [root@localhost ~]#
范例4:输出警告音
[root@localhost ~]# echo -e "hello shell\a" hello shell
取消警告音:/etc/inputrc
[root@localhost ~]# head -n 5 /etc/inputrc # do not bell on tab-completion set bell-style none ---注释去掉,并reboot系统 set meta-flag on set input-meta on
范例5:自动换行
[root@localhost ~]# echo -e "aaa\fbbb" aaa bbb ##自动换行,新行接上一行尾部 [root@localhost ~]#
范例6:给输出的结果添加颜色标记
(1) 更改字体颜色
[root@localhost ~]# echo -e "\e[31m test \e[0m" test [root@localhost ~]# echo -e "\e[32m test \e[0m" test [root@localhost ~]# echo -e "\e[33m test \e[0m" test [root@localhost ~]# echo -e "\e[34m test \e[0m" test
(2) 更改字体类型
[root@localhost ~]# echo -e "\e[1;31m test \e[0m" test [root@localhost ~]# echo -e "\e[2;31m test \e[0m" test [root@localhost ~]# echo -e "\e[3;31m test \e[0m" test [root@localhost ~]# echo -e "\e[4;31m test \e[0m" test
(3) 更改背景颜色
[root@localhost ~]# echo -e "\e[1;41m test \e[0m" test [root@localhost ~]# echo -e "\e[1;42m test \e[0m" test [root@localhost ~]# echo -e "\e[1;43m test \e[0m" test [root@localhost ~]# echo -e "\e[1;44m test \e[0m" test
3.2 历史命令
①、查看历史执行命令 语法:history [选项] [历史命令的保存文件] 选项 -c:清理历史命令 -w:保存缓存中的历史命令,如果不手工指定,默认放到:~/.bash_history中
系统默认是保存的是1000条历史命令,可以在/etc/profile中进行修改,.bash_history中保存的是上次登录操作的命令,默认只有正常注销退出后系统才会记录本次操作的记录,但是我们可以使用history -w来保存本次操作的命令,而不用退出系统,这时历史命令都被保存到了.bash_history这个文件中
[root@localhost ~]# history -w
如果需要清理历史命令和.bash_history的命令,只需要执行:
[root@localhost ~]# history -c [root@localhost ~]# history 1 history
可以看到已经没有任何的执行记录了。
export HISTSIZE=1000 # 设置内存中的history命令的个数 export HISTFILESIZE=1000 # 设置文件中的history命令的个数
②历史命令的调用
如果要使用原先已经执行的过的命令,有几种办法:
1、使用上、下方向键可以调用出历史的执行记录,逐条查看 2、使用“!n”可以执行第n条命令 3、使用“!!”可以重复执行上一条命令 4、使用“!字符串”可以执行最后一条以该字符串开头的命令 5、使用“!$” 重复执行上一条命令的最后一个参数 6、CTRL-R:搜索最近使用的以该字符串开始的命令
3.3 命令和文件的补全
可以帮助我们通过tab键来补全命令和文件【快速按两次tab键】
3.4 别名
别名的配置文件在:~/.bashrc
[root@localhost ~]# cat /root/.bashrc # .bashrc # User specific aliases and functions alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi
是配置文件生效,可以使用:
[root@localhost ~]# source .bashrc [root@localhost ~]# vim1
如果要永久有效,就将别名写在上述文件中,临时有效的话可以在shell中写:
[root@localhost ~]# alias ens33="vim /etc/sysconfig/network-scripts/ifcfg-ens33" root@localhost ~]# ens33
别名的优先级比命令高,那么执行的具体顺序是什么呢?
1、第一顺位执行使用绝对路径或者相对路径执行命令 2、第二顺位执行别名 3、第三顺位执行bash的内部命令(man bash) 4、第四顺位执行按照$PATH环境变量定义的目录查找到的第一个命令
如果都没找到就会报错。
-
注意:命令行定义的别名,只会临时生效,一旦重启系统,就会失效。 想要永久生效,必须写入配置文件:
① 打开配置文件: vi /root/.bashrc ② 编辑配置脚本:alias ip= ‘vim /etc/sysconfig/network-scripts/ifcfg-ens33’ ③保存
-
删除别名:格式:unalias 别名
3.5 bash常用快捷键
快捷键 | 说明 |
---|---|
CTRL-A | 将光标移到行首(在命令行下) |
CTRL-B | 退格 (非破坏性的),这个只是将光标位置往回移动一个位置 |
CTRL-C | 中断,终结一个前台作业 |
CTRL-D | “EOF” (文件结尾:end of file)。它用于表示标准输入(stdin)的结束。在控制台或xterm 窗口输入文本时,CTRL-D 删除在光标下的字符。从一个shell中退出 (类似于exit)。如果没有字符存在,CTRL-D 则会登出该会话。在一个xterm窗口中,则会产生关闭此窗口的效果。 |
CTRL-E | 将光标移动到行尾(在命令行下) |
CTRL-F | 将光标向前移动一个字符(在命令行下) |
CTRL-U | 擦除从光标位置开始到行首的所有字符内容。在某些设置下,CTRL-U会不以光标位置为参考而删除整行的输入 |
CTRL-Y | 将之前已经清除的文本粘贴回来(主要针对CTRL-U或CTRL-W) |
CTRL-R | 回溯搜索(Backwards search)history缓冲区内的文本(在命令行下)。注意:按下之后,提示符会变成(reverse-i-search)”:输入的搜索内容出现在单引号内,同时冒号后面出现最近最匹配的历史命令 |
CTRL-Z | 暂停一个前台的作业;在某些文本处理程序中也作为替换操作;在MSDOS文件系统中作为EOF(End-of-file)字符。 |
3.6 多条命令执行与管道符
3.6.1 连续多个命令的执行方式
多命令执行符 | 格式 | 作用 |
---|---|---|
;(分号) | 命令1;命令2 | 多个命令顺序执行,命令之间没有任何的逻辑关系 |
&& | 命令1&&命令2 | 逻辑与,当命令1正确执行后,命令2才会执行,当命令1执行不正确,命令2不执行 |
|| | 命令1||命令2 | 逻辑或,当命令1执行不正确时,则命令2才会执行,当命令1执行正确,则命令2不会执行 |
(1) 分号“;”
多个命令顺序执行,命令之间没有任何的逻辑关系,命令1执行不正确也不会影响命令2. [root@localhost ~]# ls;date 321 321~ aaa abc abc~ anaconda-ks.cfg first_shell.sh httpd-2.4.48 httpd-2.4.48.tar.gz test Mon Sep 6 16:43:14 CST 2021 [root@localhost ~]# la;date -bash: la: command not found Mon Sep 6 16:44:04 CST 2021
(2)“&&”符号
当命令1正确执行后,命令2才会执行,当命令1执行不正确,命令2不执行 [root@localhost ~]# ls && date 321 321~ aaa abc abc~ anaconda-ks.cfg first_shell.sh httpd-2.4.48 httpd-2.4.48.tar.gz test Mon Sep 6 16:45:33 CST 2021 [root@localhost ~]# la && date -bash: la: command not found
(3)“||”符号
当命令1执行不正确时,则命令2才会执行,当命令1执行正确,则命令2不会执行 [root@localhost ~]# ls || date 321 321~ aaa abc abc~ anaconda-ks.cfg first_shell.sh httpd-2.4.48 httpd-2.4.48.tar.gz test [root@localhost ~]# la || date -bash: la: command not found Mon Sep 6 16:46:37 CST 2021
3.6.2 管道符
命令格式:命令1 | 命令2
命令1的正确输出作为命令2的操作对象
示例 1:查找出系统中所有连接的地址信息
[root@localhost ~]# yum -y install net-tools [root@localhost ~]# netstat -an | grep ESTABLISHED
示例2:过滤网络状态中包好http的连接并统计连接数
[root@localhost ~]# netstat -antup|grep httpd |wc -l