1 编程基础
1.1 程序组成
程序:算法+数据结构
- 数据:是程序的核心
- 算法:处理数据的方式
- 数据结构:数据在计算机中的类型和组织方式
1.2 编程风格
1、过程式:以指令为中心来组织代码,数据服务于指令。代表:C语言,bash。
过程式编程语言三种执行逻辑:
- 顺序执行:程序按从上到下顺序执行。
- 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行。
- 循环执行:程序执行过程中需要重复执行多次某段语句。
2、对象式:以数据为中心来组织代码,指令服务于数据。代表:Java,C++,Python。
- 类(class):实例化对象,method
1.3 编程语言的分类
根据运行方式
- 编译运行:源代码 → 编译器(编译)→ 程序文件;
- 解释运行:源代码 → 运行时启动解释器,由解释器边解释边运行。
根据启编译过程中功能的实现是调用库还是调用外部的程序文件
- shell脚本编程:利用系统上的命令及编程组件进行编程;
- 完整编程:利用库或编程组件进行编程。
2 shell脚本基础
2.1 shell 脚本的用途和应用场景
用途:
- 自动化常用命令
- 执行系统管理和故障排除
- 创建简单的应用程序
- 处理文本或文件
应用场景:
- 重复性操作
- 交互性任务
- 批量事务处理
- 服务运行状态监控
- 定时任务执行
2.2 常见的shell解释器
Linux系统中的Shell 是一个特殊的应用程序,它介于操作系统内核与用户之间,充当一个”命令解释器“的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出结果。 它是用户使用 Linux 的桥梁。
Shell 既是一种命令语言,又是一种程序设计语言。
常见的 Shell 解释器程序有很多种,使用不同的 Shell 时,其内部指令、命令行提示符等方面会存在一些区别。通过/etc/shell 文件可以了解当前系统所支持的 Shell 脚本种类。
查看本机的shell信息:
[root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh /bin/csh 复制代码
linux 中常见的shell
- bash:基于GUN的框架下发展的shell
- csh:类似C语言的shell
- tcsh:整合了csh 提供了更多功能
- sh:已经被bash替换
- nologin:让用户无法登录
bash(/bin/bash)是目前大多数 Linux 版本采用的默认 shell。
bash特性:
- 支持快捷键:比如 ctrl+c 强制终止进程 、 ctrl+l 清屏 、Tab补齐 等等。
- 支持查看历史命令(history)
- 支持别名(alias)
- 标准输入和标准输出的重定向
- 管道符
- 文件名通配机制
- 支持命令hash
- 支持变量
这些功能都是bash特有的,其他shell环境没有这些功能,或者说没有这么全,所以bash取代sh成为了Linux的默认shell。
2.3 shell脚本基本结构
shell脚本就是将各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。
什么是shell脚本:
- 将要执行的命令按顺序一一列出,保存到一个文本文件,最后自动执行。
- 执行脚本需要x权限,也可以使用绝对路径来执行。
- 可结合各种Shell控制语句以完成更复杂的操作。
脚本的构成:
- 脚本申明(申明解释器) :第一行开头 “#!/bin/bash”,表示此行以下的代码语句是通过/bin/bash程序来执行。还有其他类型的解释器,比如 #/usr/bin/python、#!/usr/bin/expect 。
- 注释信息: 以“#”开头的语句表示为注释信息,被注释的语句在脚本运行时不会被执行。
- 可执行语句: 如echo命令,用于输出“ ”之间的字符串。
2.4 shell 脚本规范
脚本名称规范:文件名以.sh结尾,方便识别。
脚本代码开头约定:
- 第一行一般为调用使用的语言
- 程序名,避免更改文件名后无法找到正确的文件
- 版本号
- 更改后的时间
- 作者相关信息
- 该程序的作用,及注意事项
- 最后是各版本的更新简要说明
规范:
#!SHEBANG //首行shebang机制(#!) CONFIGURATION_VARIABLES //变量的使用 FUNCTION_DEFINITION //函数的定义 MAIN_CODE //主代码 复制代码
shell脚本范例:
#!/bin/bash # ------------------------------ # Filename: hello.sh # Version: 2.0 # Date: 2022/03/30 # Author: yu # Email: yu@gmail.com # Website: www.xxx.com # Description: say hello # Copyright: 2022 yu # License: GPL # ----------------------------- echo "hello world" 复制代码
2.5 脚本的执行方式
1、指定路径去执行文件,文件需要有执行权限。
- 绝对路径。如:/root/hello.sh
- 相对路径。如:./hello.sh
[root@localhost ~]# chmod +x hello.sh [root@localhost ~]# /root/hello.sh //使用绝对路径执行脚本 hello stars [root@localhost ~]# ./hello.sh //使用相对路径执行脚本 hello stars 复制代码
2、指定解释器去执行(bash 脚本名),不需要执行权限。
- bash 脚本名。如:bash hello.sh
- “source 脚本名” 或 “ . 脚本名”。 //不会启动子shell环境
[root@localhost ~]# chmod -x hello.sh [root@localhost ~]# ll hello.sh -rw-r--r--. 1 root root 31 3月 30 20:27 hello.sh [root@localhost ~]# bash hello.sh //bash执行脚本 hello stars [root@localhost ~]# source hello.sh //source执行脚本 hello stars [root@localhost ~]# . hello.sh // . 执行脚本 hello stars 复制代码
注意:
- 执行脚本时的shell环境:
- source和 . 执行脚本时,会在当前shell环境中执行脚本。
- bash、绝对路径、相对路径 执行脚本时,会创建一个子shell环境,并在这个子shell环境中执行脚本。
- 不建议使用source来执行脚本,可能会影响一些资源配置。
- 脚本中的空白行会被解释器忽略。
- 脚本中,除了shebang,余下所有以#开头的行,都回被视作注释行而被忽略。此即为注释行。
2.6 脚本错误调试
脚本错误类型:
- 命令错误: 命令错误不会影响接下来的命令,之后的命令会继续执行。
- 语法错误: 会导致后续的命令不执行。造成脚本中一部分命令已执行,一部分未执行。
- 逻辑错误: 执行后的效果不是自己想要的。需要自己去排查。
调试方法:
bash -n 脚本名称 //只检查语法错误,不真正执行脚本。定位的错误行可能不准确。 bash -x 脚本名称 //显示每个命令的执行过程,方便发现逻辑错误 复制代码
3 重定向与管道符
由于Shell脚本“批量处理”的特殊性,其大部分操作过程位于后台,不需要用户进行干预,因此要学会提取、过滤执行信息变得十分重要,所以我们需要重定向和管道。
3.1 标准输入与输出
当执行shell命令时,会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:
类型 | 设备文件 | 文件描述符 | 默认情况 | 对应文件句柄位置 |
标准输入 | /dev/stdin | 0 | 从键盘获得输入 | /proc/self/fd/0 |
标准输出 | /dev/stdout | 1 | 输出到屏幕(即控制台) | /proc/self/fd/1 |
错误输出 | /dev/stderr | 2 | 输出到屏幕(即控制台) | /proc/self/fd/2 |
交互式硬件设备:
- 标准输入:从该设备接收用户输入数据。
- 标准输出:通过该设备想用户输出数据。
- 标准错误:通过该设备报告执行出错信息。
3.2 重定向
重定向的意思就是,不通过标准输出到默认屏幕上,而是输出到你指定的位置。
1、输入重定向
符号 | 作用 |
命令 < 文件 | 从指定的文件读取文件,而不是从键盘输入 |
命令 << 分界符 | 从标准输入中读入,直到遇见分界符才停止 |
命令 < 文件1 > 文件2 | 将文件1 作为命令的标准输入并将标准输出到文件2 |
2、输出重定向
符号 | 作用 |
命令 > 文件 | 将标准输出结果保存到指定的文件中(覆盖原有内容) |
命令 >> 文件 | 将标准输出结果追加到指定的文件尾部 |
命令 2> 文件 | 将错误输出信息保存到指定文件中(覆盖原有内容) |
命令 2>> 文件 | 将错误输出信息追加到指定文件尾部 |
命令 > 文件 2>&1 | 混合输出,将标准输出与错误输出保存到文同一个文件中 |
命令 2> 文件 1>&2 | 同上 |
命令 &> 文件 | 同上 |
命令 >& 文件 | 同上 |
注:
- &表示混合,&> 和 >& 都表示将标准输出和错误输出重定向到同一个文件。
- 命令 > 文件 2>&1,表示把错误输出2重定向给前面的标准输出1 (前面的1被省略了),即将错误输出和标准输出保存到同一个文件中。
示例:
1)将“123456”重定向输出到 1.txt 文件中,之后再用 1.txt 文件中的内容给用户nancy设置密码。 (注意:标准输入重定向会受selinux影响,需要先关闭selinux。)
[root@localhost ~]# useradd nancy [root@localhost ~]# echo "123456" > 1.txt //标准输出重定向 [root@localhost ~]# cat 1.txt 123456 [root@localhost ~]# passwd --stdin nancy < 1.txt //标准输入重定向会受selinux影响 更改用户 nancy 的密码 。 passwd: 鉴定令牌操作错误 [root@localhost ~]# setenforce 0 //关闭selinux [root@localhost ~]# passwd --stdin nancy < 1.txt //标准输入重定向执行成功,成功为nancy设置密码 更改用户 nancy 的密码 。 passwd:所有的身份验证令牌已经成功更新。 [root@localhost ~]# 复制代码
2)将“aaa"重定向输出到 fa.txt 文件中,之后将“bbb" 输出到 fa.txt 文件中,覆盖原有的”aaa";最后将“ccc"追加到 fa.txt 文件中。
[root@localhost ~]# echo "aaa" > fa.txt //将aaa重定向输出到fa.txt [root@localhost ~]# cat fa.txt aaa [root@localhost ~]# echo "bbb" > fa.txt //将bbb输出到fa.txt,覆盖原有内容 [root@localhost ~]# cat fa.txt bbb [root@localhost ~]# echo "ccc" >> fa.txt //将ccc追加到fa.txt中 [root@localhost ~]# cat fa.txt bbb ccc 复制代码
3)使用分界符进行输入重定向。
[root@localhost /]# cat > haha.txt <<EOF //以EOF作为分界符,从标准输入中读入文件,直到遇见EOF > you > are > smart > EOF [root@localhost /]# cat haha.txt you are smart 复制代码
4)将错误输出重定向到 log 文件中。
[root@localhost ~]# la bash: la: 未找到命令... [root@localhost ~]# la 2> log //将错误输出重定向 [root@localhost ~]# cat log bash: la: 未找到命令... 复制代码
5)混合输出,将标准输出和错误输出同时重定向到文件中。
# 同时存在标准输出和错误输出 [root@localhost /]# ls /opt /xxx ls: 无法访问/xxx: 没有那个文件或目录 /opt: rh # 需要将标准输出和错误输出同时重定向到文件中 # 方法一: [root@localhost /]# ls /opt /xxx &> f1 [root@localhost /]# cat f1 ls: 无法访问/xxx: 没有那个文件或目录 /opt: rh # 方法二: [root@localhost /]# ls /opt /xxx >& f2 [root@localhost /]# cat f2 ls: 无法访问/xxx: 没有那个文件或目录 /opt: rh # 方法三: [root@localhost /]# ls /opt /xxx > f3 2>&1 [root@localhost /]# cat f3 ls: 无法访问/xxx: 没有那个文件或目录 /opt: rh # 方法四: [root@localhost /]# ls /opt /xxx 2> f4 1>&2 [root@localhost /]# cat f4 ls: 无法访问/xxx: 没有那个文件或目录 /opt: rh 复制代码
3.3 管道符
管道符的作用是连接两个命令,将第一个命令的标准输出作为第二个命令的标准输入。 同一行命令中可以使用多个管道符。
linux下的管道符使用"竖杠"表示:| 。
格式:命令A | 命令B
[root@localhost /]# ps aux | wc -l //统计进程数量 138 [root@localhost /]# echo "123123" | passwd --stdin helen //非交互式设置用户密码 更改用户 helen 的密码 。 passwd:所有的身份验证令牌已经成功更新。 [root@localhost /]# ss -ntap | grep 22 //查看22端口是否开启 LISTEN 0 128 *:22 *:* users:(("sshd",pid=1111,fd=3)) ESTAB 0 64 192.168.72.192:22 192.168.72.100:50603 users:(("sshd",pid=1203,fd=3)) ESTAB 0 0 192.168.72.192:22 192.168.72.100:50615 users:(("sshd",pid=1280,fd=3)) LISTEN 0 128 :::22 :::* users:(("sshd",pid