目录
一、shell脚本基础
1. 概述与构成
Shell脚本是一种用Shell语言编写的脚本程序,它可以在Unix/Linux系统上运行。Shell脚本通常以.sh为文件扩展名,是一种方便的自动化工具,可以用来完成各种系统管理和任务自动化的工作。
- Shebang(可选):在脚本文件的第一行可以指定Shebang,用于指定脚本使用的Shell解释器。例如,#!/bin/bash表示使用bash解释器执行脚本。
- 注释:可以在脚本中使用注释来提供说明和解释。注释以#开头,可以单行注释或多行注释。
- 变量定义:可以在脚本中定义变量,用于存储数据。变量名通常使用大写字母,等号=用于赋值。例如,name="John"定义了一个名为name的变量,并将其赋值为"John"。
- 命令和操作:在脚本中可以使用各种命令和操作,用于执行特定的任务。可以使用系统命令、自定义函数、管道、重定向等。
- 流程控制语句:可以使用流程控制语句来控制程序的执行流程。常见的流程控制语句包括if语句、for循环、while循环、case语句等。
- 函数定义(可选):可以在脚本中定义函数,用于封装一段可重复使用的代码。函数可以接受参数,并返回结果。
- 输入和输出:脚本可以接受命令行参数作为输入,并可以使用echo命令输出结果。
2. shell的作用
Linux 系统中的Shell是一个特殊的应用程序,它介于操作系统内核与用户之间,充当了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。 常见的Shell解释器程序有很多种,使用不同的Shell时,其内部指令、命令行提示符等方面会存在一些区别。通过/etc/shells文件可以了解当前系统所支持的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:让用户无法登录
3. 脚本执行逻辑及执行方式
脚本执行逻辑:
- 顺序执行:程序按从上到下顺序执行
- 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
- 循环执行:程序执行过程中需要重复执行多次某段语句
执行方式:
① 使用绝对或者相对路径执行(需要加执行权限)
[root@localhost ~]# vim ping.sh
[root@localhost ~]# chmod +x ping.sh #添加执行权限
#!/bin/bash
ping -c1 192.168.190.100
[root@localhost ~]# /root/ping.sh #绝对路径执行
[root@localhost ~]# ./ping.sh #相对路径执行
② 直接使用解释器(不需要加执行权限)
[root@localhost ~]# chmod -x ping.sh
[root@localhost ~]# bash ping.sh
③ source和 . (不需要加执行权限)
[root@localhost ~]# source ping.sh
[root@localhost ~]# . ping.sh
三种执行方式对当前环境影响:
[root@localhost ~]# vim cd.sh
#!/bin/bash
cd /opt
ls
[root@localhost ~]# chmod +x cd.sh
[root@localhost ~]# /root/cd.sh
rh
[root@localhost ~]# pwd
/root
[root@localhost ~]# ./cd.sh
rh #使用子shell执行,不切环境
[root@localhost ~]# pwd
/root
[root@localhost ~]# bash cd.sh
rh
[root@localhost ~]# pwd
/root #使用子shell执行,不切环境
[root@localhost ~]# source cd.sh
rh
[root@localhost opt]# pwd
/opt #使用本shell执行,切环境
[root@localhost ~]# . cd.sh
rh
[root@localhost opt]# pwd
/opt #使用本shell执行,切环境
4. 脚本错误调试
① 命令错误
默认后续的命令还会继续执行,用bash -n无法检查出来 ,可以使用bash -x进行观察
[root@localhost ~]# vim 1.sh
#!/bin/bash
mkdi 1 #错误命令
echo 1 #正确命令
[root@localhost ~]# bash 1.sh
1.sh:行1: mkdi: 未找到命令
1 #错误命令不影响后续命令
② 语法错误
会导致后续的命令不继续执行,可以用bash -n检查错误,提示的出错行数不一定是准确的
[root@localhost ~]# vim 2.sh
#!/bin/bash
if [ 1 -eq 1 ];then
echo t
else
echo f
#fi
[root@localhost ~]# bash 2.sh
2.sh:行7: 语法错误: 未预期的文件结尾
③ 逻辑错误
只能使用bash -x进行
注:
bash -n:脚本名称 (不在当前目录下加绝对路径),检查语法错误
bash -x:脚本名称 (不在当前目录下加绝对路径),逻辑错误
④ set -e,set -u
在 脚本的前面输入set -e一旦出错立即停止
[root@localhost ~]# vim 3.sh
#!/bin/bash
set -e
cd /op
[root@localhost ~]# bash 3.sh
3.sh: 第 3 行:cd: /op: 没有那个文件或目录
另外:set -u变量不存在不让执行
二、shell脚本应用
1. 重定向与管道符
1.1 重定向
重定向是一种功能,它允许用户更改命令的标准输入(stdin)和标准输出(stdout)的默认行为。这通常用于将命令的结果发送到不同的目的地,而不是仅仅显示在终端控制台上。
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 2 | 显示器 |
交互式硬件设备:
- 标准输入:从该设备接收用户输入的数据
- 标准输出:通过该设备向用户输出数据
- 标准错误:通过该设备报告执行出错信息
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定的文件读取数据,而不是从键盘输入 |
重定向输出 | 1> | 将输出结果保存到指定的文件(覆盖原有内容) |
>> | 将输出结果追加到指定的文件尾部 | |
标准错误输出 | 2> | 将错误信息保存到指定的文件(覆盖原有内容) |
2>> | 标准错误输出结果追加到指定的文件尾部 | |
混合输出 | &>无论对错都可以重定向 | 将标准输出、标准错误的内容保存到同一个文件中 |
案例:
不能将正确和错误一起显示出来
[root@centos7 ~]#ls /data /xxx 1> /data/all.log 2>&1
先将正确的重定向文件中,再将错误的重定向文件中
[root@centos7 ~]#ls /data /xxx 2> /data/all.log 1>&2
先将错误的重定向文件中,再将正确的重定向文件中
[root@centos7 ~]#ls /data /xxx &> /data/all.log 不解释
[root@centos7 ~]#ls /data /xxx >& /data/all.log 同上
[root@centos7 ~]#ls /data /xxx 2>&1 1> /data/all.log 开始没有定义1,所以不符合要求
1.2 多行重定向
可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个文件并用作命令的标准输入。
[root@localhost ~]# cat > test << EOF #EOF不区分大小写
> 1
> 2
> EOF
[root@localhost ~]# cat test
1
2
案例:修改密码
[root@localhost ~]# passwd fql << EOF
> 123456
> 123456
> EOF
更改用户 fql 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
1.3 管道符
“|”,将前面命令的结果当作后面命令的参数执行,管道符左边的命令一定要有标准输出,右边的命令一定可以接收标准输入。当右边无法接收标准输入,可以使用xargs命令代为接收。
[root@localhost ~]# cat /etc/passwd | wc -l
41
[root@localhost ~]# echo --help | xargs cat
用法:cat [选项]... [文件]...
将[文件]或标准输入组合输出到标准输出。
……
2. 自定义变量
2.1 常见Shell变量的类型
- 自定义变量:由用户自己定义,修改和使用
- 预定义变量:Bash中内置的一类变量shell,不能修改规定好的变量
- 环境变量:由系统维护,用于设置工作环境,当前目录 、当前主机名、$PATH
- 只读变量:只可以读取不可以更改,常量
- 位置变量:通过命令行给脚本传递参数
2.2 命名要求
- 区分大小写
- 不能使程序中的保留字和内置变量:如:if, for,hostname 命令 a=
- 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
- 不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
- 大驼峰 StudentFirstName
- 小驼峰 studentFirstName
- 下划线 student_name
定义变量:name=fql
引用变量:$name 或 ${name}
调用变量:echo $name 或 echo ${name}
取消变量:unset name
2.3 符号使用
双引号" " #弱引用,可以识别变量,可以避免空格错误
[root@localhost ~]# a=1
[root@localhost ~]# echo "$a"
1
[root@localhost ~]# a=1 2
bash: 2: 未找到命令...
[root@localhost ~]# a="1 2";echo $a
1 2
单引号' ' #强引用,不能识别变量
[root@localhost ~]# a=1
[root@localhost ~]# echo '$a'
$a
反撇号` ` #调用命令的执行结果,等于$()
[root@localhost ~]# time=`date`;echo $time
2024年 01月 24日 星期三 16:16:19 CST
大括号{ } #定义变量名的范围
[root@localhost ~]# a=1;b=2
[root@localhost ~]# echo ${a}b
1b
2.4 变量追加值
格式:变量名+=变量值
[root@localhost ~]# a=1
[root@localhost ~]# a+=2;echo $a
12
2.5 read -p
从键盘输入的内容变成变量,交互式命令
[root@localhost ~]# read -p "现在的时间是:" time
现在的时间是:16点
[root@localhost ~]# echo $time
16点
[root@localhost ~]# vim 1.sh
#!/bin/bash
read -p "你的名字:" name
echo "你的名字是:$name"
[root@localhost ~]# bash 1.sh
你的名字:lisi
你的名字是:lisi
3. 变量作用范围
默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或新的shell环境中,局部变量将无法再起作用。可以通过内部命令export将指定的变量为全局变量,使用户定义的变量在所子shell环境中可以继续使用。
方法:
格式1:定义好变量情况下 export 变量名
格式2:为定义变量情况下 export 变量名=变量值
[root@localhost ~]# a=1
[root@localhost ~]# echo $a
1
[root@localhost ~]# bash #切换到子shell
[root@localhost ~]# echo $a #子shell无法识别变量
[root@localhost ~]#
[root@localhost ~]# pstree -p | grep -v grep | grep bash
|-sshd(1097)-+-sshd(1520)---bash(1583)---bash(37606) #37606为新打开的子shell
[root@localhost ~]# export a #定义全局变量
[root@localhost ~]# bash
[root@localhost ~]# echo $a #子shell可以识别变量
1
[root@localhost ~]# pstree -p | grep -v grep | grep bash
|-sshd(1097)-+-sshd(1520)---bash(1583)---bash(37654) #37654为新打开的子shell
4. 变量的运算
4.1 expr整数运算
expr只能进行整数的运算,格式:expr 变量1 运算符 变量2 [运算符 变量3]
运算符:
- 加法 +
- 减法 -
- 乘法 \ *
- 除法 /
- 取余 (取模)%
[root@localhost ~]# expr a+b
a+b
[root@localhost ~]# expr $a + $b
3
[root@localhost ~]# expr $a - $b
-1
[root@localhost ~]# expr $a \* $b
2
4.2 其他运算方法
let 变量名=算术表达式
[root@localhost ~]# a=1;b=2
[root@localhost ~]# let c=a+b;echo $c
3
((变量名=算术表达式))
[root@localhost ~]# a=1;b=2
[root@localhost ~]# ((c = a+b));echo $c
3
变量名=$[算术表达式]
[root@localhost ~]# a=1;b=2
[root@localhost ~]# c=$[c=a+b];echo $c
3
变量=$(expr arg1 + arg2 ...)
[root@localhost ~]# c=$(expr $a + $b);echo $c
3
变量=`expr arg1 + arg2 ...`
[root@localhost ~]# c=`expr $a + $b`;echo $c
3
echo 算术表达式 | bc
[root@localhost ~]# echo $a+$b | bc
3
4.3 随机数生成器变量
$RANDOM
是一个特殊的环境变量,用于生成一个随机整数。每次访问$RANDOM
时,它会返回一个0到32767(2^15-1)之间的随机整数,这个值是通过使用伪随机数生成器来生成的。
[root@localhost ~]# echo $[RANDOM] #随机生成0-32767
17922
[root@localhost ~]# echo $[RANDOM%35] #随机生成0-34
1
[root@localhost ~]# echo $[RANDOM%35+1] #随机生成1-35
7
随机生成颜色:
[root@localhost ~]# echo -e "\E[1;30mhello\E[0m"
hello
#指定颜色,30-36共7种颜色
[root@localhost ~]# echo -e "\E[1;$[RANDOM%7+31]mhello\E[0m"
hello
#随机颜色
5. 环境变量
5.1 概述特点
环境变量大体可以分为两类:全局环境变量、局部环境变量。前者变量名通常使用大写字母,后者变量名通常使用小写字母。可通过下述env、printenv命令查看当前所有的全局环境变量。
常用的环境变量:
- $USER 表示用户名称
- $HOME 表示用户的宿主目录
- $LANG 表示语言和字符集
- $PWD 表示当前所在工作目录
- $PATH 表示可执行用户程序的默认路径
特点:
- 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
- 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
- 一般只在系统配置文件中使用,在脚本中较少使用
5.2 配置文件
/etc/profile如果修改此文件会作用于所有用户
~/.bash_profile 用户独立的配置文件,修改这个文件只作用于当前用户
6. 只读变量
只读变量是一种特殊类型的变量,其值不能被修改或重写。一旦将变量声明为只读,就无法再对其进行赋值操作。 变量值不允许修改(重新赋值)的情况,无法使用unsets删除,最快方法重启。
[root@localhost ~]# a=1
[root@localhost ~]# readonly a
[root@localhost ~]# echo $a
1
[root@localhost ~]# a=2
bash: a: 只读变量
[root@localhost ~]# unset a
bash: unset: a: 无法反设定: 只读 variable
7. 位置变量
位置变量也称为位置参数,使用$1、$2、$3、…、$9 表示
[root@localhost ~]# vim 1.sh
#!/bin/bash
echo "$1" 位置1
echo "$2" 位置2
echo "${10}" 位置10,不使用括号,只能识别第一个参数
[root@localhost ~]# bash 1.sh {1..20}
1
2
10
8. 预定义(状态)变量
存在一些预定义变量(也称为状态变量),它们提供了有关系统和正在发生的操作的信息。这些变量不需要事先声明,而是由操作系统自动提供。
- $*:表示所有位置参数的内容看成一个整体返回 返回所有
- $@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
- $?:表示前一条命令执行后的返回状态,返回值为0表示执行正确,返回任何非0值均表示执行出现异常
- $#:表示命令行中位置参数的总个数
- $0:表示当前执行的脚本或程序的名称 当前脚本的名字
- $$:当前bash的进程id
- $!: 后台任务最后一个id
[root@localhost ~]# vim 1.sh
#!/bin/bash
echo "$*"
echo "$@"
echo "$?"
echo "$#"
echo "$0"
echo "$$"
echo "$!"
[root@localhost ~]# bash 1.sh {1..10}
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
0
10
1.sh
38866
注:
当使用“$0”预定义变量时,如果执行的是软链接文件,则输出的是当前执行的软链接文件名
[root@localhost ~]# ln -s 1.sh a
[root@localhost ~]# ll a
lrwxrwxrwx. 1 root root 4 1月 24 18:47 a -> 1.sh
[root@localhost ~]# bash a
a