shell脚本基础
1.shell概述
shell脚本的概念
- 将要执行的命令按顺序保存到一个文本文件
- 给该文件可执行权限
- 可结合各种shell控制语句以完成更复杂的操作
shell应用应用场景
- 重复性操作
- 交互性操作
- 批量事务处理
- 服务运行状态监控
- 定时任务执行应用场景
shell的作用
Linux系统中的shell是一个特殊的应用程序,它介于操作系统内核与用户之间,充当了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。
2.用户的登录shell
常见的shell解释器程序有很多种,使用不同的shell时,其内部指令、命令行提示符等方面会存在一些区别。通过/etc/shells文件可以了解当前系统所支持的shell脚本种类。
- 登录后默认使用的shell程序,一般为/bin/bash
点击查看代码
[root@node1 ~]# cat /etc/shells //查看当前的系统支持的shell
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
linux中常见的shell:
- bsah:基于gun的框架下发展的shell
- csh:类似c语言的shell
- tcsh:整合了csh提供了更多功能
- sh:已经被bash替换
- nolongin:让用户无法登录
3.shell脚本的构成
- 脚本申明(申明解释器):第一行开头“#!/bin/bash”,表示此行以下的代码语句是通过/bin/bash程序来执行的。还有其他类型的解释器,比如#/usr/bin/python、#!/usr/bin/expect(免交互)。
- 注释信息:以“#”开头的语句表示为注释信息,被注释的雨具在脚本运行时不会被执行
- 可执行语句:如echo命令,用于输出“”之间的字符串。
点击查看代码
例:
#!/bin/bash //解释器
#this is test //注释
echo "hello world" //执行的命令
4.脚本执行逻辑及执行方式
脚本执行逻辑:
- 顺序执行:程序按从上到下顺序执行
- 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
- 循环执行:程序执行过程中需要重复执行多次某段语句
脚本执行方式:
- 1直接使用shell程序来读取脚本中的命令,不需要执行权限
点击查看代码
`bash 脚本名`
[root@node1 ~]# bash test.sh //执行脚本
this is test
点击查看代码
`绝对路径。如:/~/test.sh`
`相对路径。如:./test.sh`
[root@node1 ~]# chmod +x test.sh //添加执行权限
[root@node1 ~]# ~/test.sh //绝对路径执行脚本
this is test
[root@node1 ~]# ./test.sh //相对路径执行脚本
this is test
- 3使用“source脚本名”或“.脚本名”执行脚本,不需要权限
1和2执行方式不会影响当前环境中bash设置,会开启一个全新的bash环境执行脚本
3不推荐使用,不会启动子shell环境,会影响当前bash环境中的配置
5.常见脚本错误
脚本错误类型:
- 命令错误:命令错误不会影响接下来的命令继续执行。
- 语法错误:会导致后续的命令不执行。造成脚本中一部分命令已执行,一部分未执行
- 逻辑错误:执行后的效果不是自己想要的。需要自行排查
调试方法:
点击查看代码
命令错误调试:
在脚本的前面输入 `set -e` ,一旦出错立即停止
bash -n 脚本名称 //只检查语法错误,不真正执行脚本。定位的错误行可能不准确。
bash -x 脚本名称 //显示每个命令的执行过程,方便发现逻辑错误
重定向与管道符
1.标准输入、输出
当执行shell命令时,会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:
- 标准输入:从该设备接收用户输入的数据
- 标准输出:通过该设备向用户输出数据
- 标准错误:通过该设备报告执行出错信息
类型 | 设备文件 | 文件描述编号 |
---|---|---|
标准输入 | /dev/stdin | 0 |
标准输出 | /dev/stdout | 1 |
标准错误输出 | /dev/stderr | 2 |
重定向
重定向的意思就是,不输出到默认设备上,输出到你指定的位置(文件、其他输出设备)
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定的文件读取数据,而不是从键盘输入 |
重定向输出 | 1> | 将输出结果保存到指定的文件(覆盖原有内容) |
>> | 将输出结果追加到指定的文件尾部 | |
标准错误输出 | 2> | 将错误信息保存到指定的文件(覆盖原有内容) |
2>> | 标准错误输出结果追加到指定的文件尾部 | |
混合输出 | &>无论对错都可以重定向 | 将标准输出、标准错误的内容保存到同一个文件中 |
- &表示混合,&>和>&都表示将标准输出和错误输出重定向到同一个文件。
- 命令>文件2>&1,表示把错误输出2重定向给前面的标准输出1(前面的1被省略了),即将错误输出和标准输出保存到同一个文件中。
管道符
管道符的作用是连接两个命令,将第一个命令的标准输出作为第二个命令的标准输入。同一行命令中可以使用多个管道符。
格式:cmd1|cmd2
变量
1.变量基础
常见shell变量的类型
- 自定义变量:由用户自己定义,修改和使用
- 预定义变量:Bash中内置的一类变量,系统预先设置好的,一般不可以修改
- 环境变量:和系统环境有关的变量,由系统维护,用于设置工作环境($PATH)
- 只读变量:只可以读取不可以更改(常量)
- 位置变量:通过命令行给脚本传递参数
系统内置变量:PATH,UID,HOSTNAME,USER
变量的命令要求
- 区分大小写
- 不能使程序中的保留字和内置变量:如:if, for,hostname 。
- 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反。
- 不要使用内置的变量,使用英文尽量使用词义通俗易懂,如 PATH 。
- 大驼峰 StudentFirstName
- 小驼峰 studentFirstName
- 下划线 student_name
点击查看代码
name='value'
变量名=变量值
直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
四大符号
点击查看代码
{ } 花括号 :确定变量其实起始结束的范围,只要有变量就加!
“ ” 双引号 :弱引用 smart,可以识别变量
‘ ’ 单引号 :强引用 stupid,不识别变量 (里面什么内容就输出什么内容)
` ` 反撇 :调用命令执行结果 ,效果与 $( ) 相同
2.自定义变量
取消变量:unset 变量名
追加变量的值:1变量名+=追加值 2重新定义
read -p
自定义变量:read [-p "提示信息"] 变量名
点击查看代码
[root@node1 ~]# vim test2.sh //编写脚本
#!/bin/bash
read -p "请输入一个正整数" a //自定义变量
read -p "请输入第二个正整数" b
expr $a + $b //expr只支持正整数
[root@node1 ~]# bash test2.sh //执行脚本
请输入一个正整数22
请输入第二个正整数33
55
设置变量的作用范围
默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或新的shell环境中,局部变量将无法再起作用。
可以通过内部命令export将指定的变量为全局变量,使用户定义的变量在所子shell环境中可以继续使用。
方法:
- 格式1:export 变量名
- 格式2:export 变量名=变量值
点击查看代码
`export作用:让子shell识别变量`
[root@node1 ~]# abc=123 //设置局部变量abc
[root@node1 ~]# echo $abc //查看变量
123
[root@node1 ~]# bash //进入子shell
[root@node1 ~]# echo $abc //查看变量
//为空,无效
[root@node1 ~]# exit //ctrl+D 退出子shell
[root@node1 ~]# echo $abc
123
[root@node1 ~]# export abc //export 变量名 :定义全局变量
[root@node1 ~]# bash //进入子shell
[root@node1 ~]# echo $abc //查看变量
123 //全局变量生效
输入bash进入子shell
ctrl+D组合exit 退出子shell
可以使用pstree 查看shell的环境
shell中的运算
- 运算内容:1加+2减-3乘*4除/5取余(取模)%
- 运算符号:$[]和$(())
- 运算命令:expr和let
- 运算工具:bc(系统自带)
注意:默认情况下bash只支持整数运算,只有bc能算小数
点击查看代码
`$[算术表达式]`
echo $[算术表达式] //调用
随机数生成器变量$RANDOM (取值范围:0-32767)
[root@node1 ~]# echo $[RANDOM%28] //随机取0~27
13
[root@node1 ~]# echo $[RANDOM%28+1] //随机取1~28
22
`expr`
[root@node1 ~]# expr 1+2
1+2
[root@node1 ~]# expr 1 + 2 //注意空格!加减乘除前后要有空格
3
`let`
`特殊符号运算:`
[root@node1 ~]# i=1
[root@node1 ~]# let i++ //i++ 自加1
[root@node1 ~]# echo $i
2
[root@node1 ~]# let i-- //i-- 自减1
[root@node1 ~]# echo $i
1
[root@node1 ~]# let i+=3 //i+-3 自加3
[root@node1 ~]# echo $i
4
求1~100的偶数和:
[root@node1 ~]# seq -s + 0 2 100|bc //从0开始,步长为2,取到100,求和
2550
求1~100的奇数和:
[root@node1 ~]# seq -s + 1 2 100|bc //从1开始,步长为2,取到100,求和
2500
`bash只能执行1次,使用eval命令可以执行2次`
[root@node1 ~]# n=10
[root@node1 ~]# echo {1..$n}
{1..10} //bash执行1次效果
[root@node1 ~]# echo {1..10}
1 2 3 4 5 6 7 8 9 10 //bash执行2次效果
[root@node1 ~]# eval echo {1..$n} //使用eval命令可以让bash执行2次
1 2 3 4 5 6 7 8 9 10
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。
该命令适用于那些一次扫描无法实现其功能的变量,该命令对变量进行两次扫描。
实验:system_info脚本
点击查看代码
[root@node1 ~]# vim system_info.sh //编写脚本
#!/bin/bash
PURPLE="\E[1;35m"
YELLOW="\E[1;33m"
END="\E[0m"
echo -e "$YELLOW----------------------Host systeminfo--------------------$END"
echo -e "HOSTNAME: $PURPLE`hostname`$END"
echo -e "IPADDR: $PURPLE` ifconfig ens33|grep netmask| tr -s " " |cut -d " " -f3 `$END"
echo -e "OSVERSION: $PURPLE`cat /etc/redhat-release`$END"
echo -e "KERNEL: $PURPLE`uname -r`$END"
echo -e "CPU: $PURPLE`lscpu|grep '型号名称:'|tr -s ' '|cut -d : -f2`$END"
echo -e "MEMORY: $PURPLE`free -h |grep Mem |tr -s " " |cut -d " " -f2`$END"
echo -e "DISK: $PURPLE`lsblk |grep disk |tr -s " " |cut -d " " -f4`$END"
echo -e "$YELLOW---------------------------------------------------------$END"
环境变量
1.由系统提前创建,用来设置用户的工作环境
2.可以使用env命令查看所有环境变量
3.需要记住的常用环境变量:
- $USER 表示用户名称
- $HOME 表示用户的宿主目录
- $LANG 表示语言和字符集
- $PWD 表示当前所在工作目录
- $PATH 表示可执行用户程序的默认路径
环境变量的特性:
- 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量。
- 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程。
- 一般只在系统配置文件中使用,在脚本中较少使用。
环境变量的配重文件
自定义的环境变量只是临时生效,退出系统后就会失效。需要将自定义的环境变量放入配置文件中,才会永久生效。配置文件可以用来长期变更或设置环境变量。
- 全局配置文件: /etc/profile (修改此文件会作用于所有用户)
- 用户独立的配置文件: ~/.bash_profile (修改这个文件只作用于当前用户)
只读变量
我们在定义shell变量时,默认定义的变量是可以被修改的,但有一种变量是不能修改的,就是只读变量。
只读变量只能被赋值一次。只读变量在取得初始值之后,只能进行读取操作,不能重新赋值或删除。
点击查看代码
[root@node1 ~]# name=lisi //定义一个变量name
[root@node1 ~]# readonly name //使用 readonly 修饰该变量 ,表明只读
[root@node1 ~]# echo $name
lisi
[root@node1 ~]# name=zhangsan //无法重新赋值
-bash: name: 只读变量
[root@node1 ~]# unset name //无法使用unset删除
-bash: unset: name: 无法反设定: 只读 variable
位置变量
位置变量也称为位置参数。使用$n表示,n为数字序列号,且必须为整数。
如:$1、$2、…、$9 、${10}、${11}。
两位数需要加花括号 {},不然$10会被识别为:$1和0 。
点击查看代码
[root@node1 ~]# vim weizhi.sh
#!/bin/bash
echo "$1" //显示位置1的参数
echo "$2" //显示位置2的参数
echo "${10}" //显示位置10的参数
echo "$10"
[root@node1 ~]# bash weizhi.sh {a..z}
a //对应$1
b //对应$2
j //对应$10
a0 //$10被识别为$1和0
预定义变量
预定义变量是系统定义好的变量,用来保持脚本程序的执行信息。可以直接使用。
预定义变量 | 含义 |
---|---|
$? | 上次执行命令的结果是否正确,0是正确,非0不正确 |
$0 | 当前脚本的名称 |
$$ | 当前shell进程的pid号 |
$# | 表示命令行中位置参数的总个数 |
$@ | 把所有位置参数当作个体返回 |
$* | 表示所有位置参数的内容看成一个整体返回 |
点击查看代码
[root@node1 ~]# cat yudingyi.sh
#!/bin/bash
echo "当前脚本名称:$0"
echo "当前程序的PID:$$"
echo "位置参数的个数为:$#"
echo "显示所有的位置参数(个体):$@"
echo "显示所有的位置参数(整体):$*"
[root@node1 ~]# bash yudingyi.sh {0..10}
当前脚本名称:yudingyi.sh
当前程序的PID:14772
位置参数的个数为:11 //0~10的个数
显示所有的位置参数(个体):0 1 2 3 4 5 6 7 8 9 10
显示所有的位置参数(整体):0 1 2 3 4 5 6 7 8 9 10