一.编程基础
1.程序基本概念
- Linux内核的编写者Linus Tovarls曾经说过:Talk is cheap, show me the code.(用代码说话);所以学shell编程的唯一办法就是写shell程序,不断的写写写。
- shell 编程基础主要涉及变量、基本算术运算、条件测试和条件判断等编程基础知识。在正式学习shell编程之前先了解一些程序相关的基本概念。
程序的概念:
程序:程序本质上是一系列的数据结构加上处理这些数据的算法形成的,程序的核心就是数据结构。
算法:使用程序描述的处理数据的方式
数据结构:数据在计算机中的类型和组织方式(数据在内存中的存储和组织方式)
编写程序时有多种程序编程风格:
过程式:以指令为中心,数据服务于指令
对象式:以数据为中心,指令服务于数据
2.不同的程序的执行方式
- 计算机只能识别二进制指令;
- 低级编程语言:
机器语言:由二进制的0和1的序列组成,称为机器指令;与自然语言差异太大,难懂、难写
汇编语言:用一些助记符号替代机器指令,称为汇编语言
如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中
汇编语言写好的程序需要汇编程序转换成机器指令
汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言
- 高级编程语言
高级语言又有解释型和编译型语言;
编译型语言:高级语言-->编译器-->机器代码-->执行
如:C,C++
解释语言:高级语言-->执行-->解释器-->机器代码
如: shell,python,php,JavaScript,perl,Ruby
3.编译型语言和解释型语言
- 编译型语言将源码编译为二进制可执行文件后由计算机运行,运行时无需源码
- 解释型语言是在程序运行时一条一条的将代码解释为计算机可识别的指令,运行时需要源码
- 对比
编译型语言 | 解释型语言 |
---|---|
c,c++,Delphi,Rust | shell,python,php,JavaScript,perl,Ruby |
一次性将源码编译为机器指令 | 在程序执行时才一条一条的将源代码转换为机器指令 |
高性能,运行速度快 | 支持夸平台,运行速度慢 |
在语言编译阶段可以做充分的优化 | 不需要编译阶段,直接执行代码 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vsv2eEFo-1570714759925)(png/different_language.png)]
二.shell脚本基础
1.shell脚本的基本结构
- 脚本的基本结构
SHEBANG # SHEBANG机制,指明解释该脚本的shell程序
CONFIGURATION_VARIABLES # 在写明解释器后,接着的行一般用来声明一些变量
FUNCTION_DEFINITIONS # 接着定义函
MAIN_CODE # 接着是脚本内容
2.hell脚本格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
- shell脚本的用途有:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
- 创建shell脚本
第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
示例:#!/bin/bash
添加注释
注释以#开头
第二步:运行脚本
给予执行权限,在命令行上指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行
- 脚本代码开头约定
1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明
- shell脚本示例
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 0.99
# Date: 2019/09/18
# Author: steve
# Email: steve@gmail.com
# Website: suosuoli.cn
# Description: This is my first script.
# Copyright: 2019 steve
# License: GPL
# ------------------------------------------
echo -e “Hello world! I'm a programmer now! Wow!”
3.脚本调试
检测脚本中的语法错误
bash -n /path/to/some_script
调试执行
bash -x /path/to/some_script
三.变量
1.bash中变量的种类
- 在shell中根据变量的生效范围等标准划分下面变量类型
局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
位置变量:$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:$?, $0, $*, $@, $#,$$
$? 存储脚本、命令或者函数的退出状态值;脚本的退出状态为脚本中最后一条命令的退出状态;函数退出状态也为最后一条命令的退出状态;一般成功执行退出状态为0;命令执行失败退出状态为1-255之间的整数.
$0 执行脚本时脚本的路径名
$* 将所有位置参数视为单个字符串
$@ 每个位置参数存储为单独引用的字符串,分开对待每个位置参数
$# 脚本后所跟的参数的个数
$$ 为PID变量,存储其出现在的脚本所属的进程的进程号
```bash
[root@centos7 ~]$ pstree -p |grep sshd.*bash
|-sshd(1164)---sshd(1842)---bash(1848)---bash(6007)-+-grep(6043)
[root@centos7 ~]$ echo $$ # 当前所在bash进程为6007
6007
[root@centos7 ~]$exit # 退出6007号bash进程
exit
[root@centos7 ~]$echo $$ # 此时$$记录1848
1848
- 局部变量赋值和引用
变量赋值:name='value'
(1) 可以是直接字串:name='root'
(2) 变量引用:name="$USER"
(3) 命令引用:name=`COMMAND`
name=$(COMMAND)
变量引用:${name} 或者 $name
-
显示已定义的所有变量使用set命令
-
删除变量:unset name
2.练习
- 1、编写脚本 systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小
#!/bin/bash
#
#*******************************************************************************
#Author: steveli
#QQ: 1049103823
#Data: 2019-10-06
#FileName: systemInfoForCentos678.sh
#URL: https://blog.csdn.net/YouOops
#Description: Show some sys info.
#Copyright (C): 2019 All rights reserved
#*******************************************************************************
R_SEED=$(( $RANDOM%7+31 ))
COLOR_START="\e[1;${R_SEED}m"
COLOR_END="\e[0m"
echo -e "The hostname is: ${COLOR_START}`hostname`. ${COLOR_END}"
echo -e "IPV4 addr is: ${COLOR_START}`ifconfig | egrep -o '([0-9]{1,3}\.){3}[0-9]{,3}' |head -n1` ${COLOR_END}"
echo -e "The OS version is: ${COLOR_START}`cat /etc/redhat-release | egrep -o '[0-9]+\.[0-9]+(\.[0-9]+)?'` ${COLOR_END}"
echo -e "The kernel version is: ${COLOR_START}` uname -r `. ${COLOR_END}"
free -h |grep "Mem" | tr -s " " |cut -d" " -f2,4 > /tmp/total_free
TOTAL=`cat /tmp/total_free | cut -d" " -f1`
FREE=`cat /tmp/total_free | cut -d" " -f2`
echo -e "The total online memory is: ${COLOR_START}$TOTAL(${FREE} free)${COLOR_END}"
echo -e "\nHarddisk usage: ${COLOR_START} \n\n`df -h | egrep -e /dev/sd -e /dev/nvme` ${COLOR_END}"
unset R_SEED COLOR_START COLOR_END
unset TOTAL FREE
2、编写脚本 backup.sh,可实现每日将/etc/目录备份到/backup/etcYYYY-
mm-dd中
#!/bin/bash
#
#*******************************************************************************
#Author: steveli
#QQ: 1049103823
#Data: 2019-10-07
#FileName: backup.sh
#URL: https://blog.csdn.net/YouOops
#Description: Test scrpting.
#Copyright (C): 2019 All rights reserved
#*******************************************************************************
DIR="/data/backup/"
echo "Backup starting ..."
sleep 1
cp -av /etc/ ${DIR}etc`date +%F`
echo -e "\e[1;32mBackup finished."
echo -e "The backup file located at : ${DIR} \a\e[0m"
3、编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值
#!/bin/bash
#
#*******************************************************************************
#Author: steveli
#QQ: 1049103823
#Data: 2019-10-07
#FileName: disk.sh
#URL: https://blog.csdn.net/YouOops
#Description: Test scrpting.
#Copyright (C): 2019 All rights reserved
#*******************************************************************************
MAX=`df -h | grep -E /dev/\(sd\|nvme\) | egrep -o "[0-9]{,3}%" | cut -d% -f1 | sort -nr | head -n1`
echo "The max usage of space is $MAX(%)."
4、编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序
#!/bin/bash
#
#*******************************************************************************
#Author: steveli
#QQ: 1049103823
#Data: 2019-10-07
#FileName: backup.sh
#URL: https://blog.csdn.net/YouOops
#Description: Test scrpting.
#Copyright (C): 2019 All rights reserved
#*******************************************************************************
if [[ $# -gt 0 ]]; then
FILE=$1
cat ${FILE} |grep ESTAB | tr -s " " | cut -d" " -f5 | cut -d: -f1 | sort | uniq -c | sort -nr
elif [[ $# -eq 0 ]]; then
ss -tun |grep ESTAB | tr -s " " | cut -d" " -f6 | cut -d: -f1 | sort | uniq -c | sort -nr
fi
3.环境变量
- 环境变量的声明、赋值
export name=VALUE
declare -x name=VALUE
- 变量引用
$name, ${name}
- 显示所有环境变量
env
printenv
export
declare -x
- 删除变量
unset name
4.bash内建的环境变量
PATH
SHELL
USER
UID
HOME
PWD
SHLVL
LANG
MAIL
HOSTNAME
HISTSIZE
_ :下划线
5.只读和位置变量
-
只读变量:只能声明,但不能修改和删除
-
声明只读变量:
-
- readonly name
-
- declare -r name
-
查看只读变量:
-
- readonly -p
-
位置变量:在脚本代码中调用通过命令行传递给脚本的参数
$1, $2, ...
对应第1、第2等参数,shift [n]换位置
$0
命令本身
$*
传递给脚本的所有参数,全部参数合为一个字符串
$@
传递给脚本的所有参数,每个参数为独立字符串
$#
传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异
set -- 清空所有位置变量
- 在linux中,进程使用退出状态来报告成功或失败;存储退出状态的环境变量使用 ? ; ?; ?;?存储的值范围为0-255。
0 代表成功
1-255代表失败
示例:
ping -c1 -W1 hostdown &> /dev/null
echo $?
- bash允许自定义退出状态码
bash自定义退出状态码
exit [n]:自定义退出状态码
注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命
令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执
行的最后一条命令的状态码
四.bash-shell脚本的基本算术运算
- bash中的算术运算使用let命令
基本的运算符包括:
+, -, *, /, %取模(取余), **(乘方),乘法符号有些场景中需要转义
- 实现算术运算
(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
- bash有内建的随机数生成器变量:$RANDOM(0-32767)
示例:生成 0 - 49 之间随机数
echo $[$RANDOM%50]
- bash也支持增强型赋值
增强型赋值:
+=, -=, *=, /=, %=
let varOPERvalue
例如:let count+=3
自加3后自赋值
自增,自减:
let var+=1
let var++
let var-=1
let var--
- 练习
1、编写脚本 sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的UID之和
#!/bin/bash
#
#*******************************************************************************
#Author: steveli
#QQ: 1049103823
#Data: 2019-10-06
#FileName: sumid.sh
#URL: https://blog.csdn.net/YouOops
#Description: Test scrpting.
#Copyright (C): 2019 All rights reserved
#*******************************************************************************
id1=`cat /etc/passwd | head -n10 | tail -n1 | cut -d: -f3`
i