目录
1. 概述
shell脚本的概念:
我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包括ls、cd、pwd等等。总结来说,Shell是一个命令解释器,它通过接受用户输入的Shell命令来启动、暂停、停止程序的运行或对计算机进行控制。
shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。
shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序。
shell脚本:
shell脚本是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,给该文件可执行权限,可结合各种Shell控制语句以完成更复杂的操作
shell脚本应用场景:
重复性操作
交互性任务
批量事物处理
服务运行状态监控
定时任务执行
2.shell 脚本的编写
2.1 shell 使用环境
使用命令:cat /etc/shells 可以查看到系统可用的shell 环境,可以知道bash 比sh 更高级一点,bash 比较人性化,直观,也可以自己安装ksh csh这些
2.2 shell的编写
2.2.1 注释
“# ”开头的就是注释,被编译器忽略
单行注释: #
多行注释: :<<COMMENT …COMMENT 或者
:<<! … !
(:<< 标识多行注释开始,并指定一个标识符作为开始结束的标志)
2.2.2 修改权限并运行
例如:现有脚本test.sh , 运行脚本:
1.修改权限才可以执行:chmod +x test.sh
2.如果不更改权限,本身没有可执行权限,调用解释器
(查看区别,可再开端口,输入不同的命令 pstree 可以查看到不同的环境)
新开的另一个新的shell 环境运行:
bash test.sh
sh test.sh
基于当前的shell 环境运行:
source test.sh
. test.sh
2.2.3 尝试编写脚本文件
1.按照惯例,学习任何一个语言,首先输出的便是hello world
在根目录下,新建一个文本文件test.sh (注意,这个后缀名并不代表文件的类型,是便于使用者参考,知道这个是什么文件,是一个脚本文件)
[root@localhost ~]# vim test.sh
#!/bin/bash
#第一个脚本
#日期:2021-06-01
echo "hello world "
然后保存退出,可以看到权限不够,这里要加入权限,在执行即可
脚本语言自查方法:
语言 | 功能 |
---|---|
bash -x | 逐行调试,定位到准确错误 |
bash -n | 检查语法的错误 |
2.创建一个用户并查看是否成功
[root@localhost ~]# vim user.sh
#!/bin/bash
#这是一个创建用户的脚本
#日期:2021-06-01
user=zhangsan
pass=123
useradd $user
echo "$pass" | passwd --stdin $user
然后保存退出,运行脚本查看是否成功
3.安装yum本地源
[root@localhost ~]# vim yum.sh
#!/bin/bash
#部署本地yum源
#日期:2021-06-01
mount /dev/sr0 /mnt
cd /etc/yum.repos.d/
mkdir repo.bak
mv * repo.bak/
echo "[centos7]
name=centos7
baseurl=file:///mnt
enable=1
gpgcheck=0">>/etc/yum.repos.d/repo.repo
yum clean all
yum makecache
yum repolist
效果如图:
4.实现效果图
代码如下:
[root@localhost ~]# vim 123.sh
#!/bin/bash
#这是一个小练习题
#2021-06-01
jincheng=`ps aux | wc -l`
usernum=`who | wc -l `
date=`date '+%Y-%m-%d %H:%M'`
echo -e "\e[1;29m#----------------------------------------------\e[1;70H#\e[0m"
echo -e "\e[1;30m# System Info Table \e[2;70H#\e[0m"
echo -e "\e[1;31m# read -p "当前登录用户为":$USER \e[3;70H#\e[0m"
echo -e "\e[1;32m# read -p "当前登录目录为":$PWD \e[4;70H#\e[0m"
echo -e "\e[1;33m# read -p "当前登陆主机为":$HOSTNAME \e[5;70H#\e[0m"
echo -e "\e[1;34m# read -p "当前系统时间为":$date \e[6;70H#\e[0m"
echo -e "\e[1;35m# read -p "当前系统运行的进程数":$jincheng \e[7;70H#\e[0m"
echo -e "\e[1;36m# read -p "当前系统登录的用户数":$usernum \e[8;70H#\e[0m"
echo -e "\e[1;37m# read -p "任何问题请联系":123456 \e[9;70H#\e[0m"
echo -e "\e[1;38m#----------------------------------------------\e[10;70H#\e[0m"
效果图:
3. 变量
变量类型
自定义变量:变量名=变量值
变量名:字母,数字,下划线,不可以出现特殊符号
不能以数字开头,区分大小写
变量值无所谓
环境变量:系统自己设定好的,不需要人为更改,一般是大写的
位置变量:后面可传递参数给脚本里面的内容
预定义变量:预先定义好的变量,用户只能使用,不能创建
set: 查看系统所有的变量,包括环境变量和自定义变量(没有单
独查看自定义变量的命令,可以set管道过滤)
3.1 自定义变量
3.1.1 变量操作
变量的赋值方法为: 先写变量名称,紧接着是 “=” ,最后是值。中间无任何空格。 通过echo命令加上 $变量名,即可输出变量的值。 双引号,以防止出错变量的值一般要加上。
普通赋值: name=“test” (=两边不可有空格)
作用范围只能在当前shell ,其他的shell 环境是看不到的
使用变量: echo $name 或者 echo ${name} (推荐使用大括号版)
删除赋值:unset name
只读变量:name=test ->
readonly name
(使用readonly标识后的变量,不可被修改,不可被删除,只能重新换个shell环境继续操作)
对于常规变量的字符串定义变量值应加双引号,并且等号前后不能有空格,需要强引用的,则用单引号(‘’),如果是命令的引用,则用反引号(``)
单引号:里面有特殊符号的时候,显示原来的样子,禁止引用其他变量值,$ 视为普通字符
双引号:里面有特殊符号的时候,体现转义之后的内容,允许通过$符号引用其他变量值
反撇号:用于命令替换
read “提示信息” 变量名 #交互式赋值方法
命令 | 功能 |
---|---|
read -p | “输入你的名字” |
read -n 5 | 5个字符 |
read -s -p | 静默模式,一般用在输入密码 |
3.2 环境变量
环境变量是全局变量
查看多少系统环境变量 env
看单个的环境变量 echo $ 变量名
为了使用户定义的变量在所有的子Shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export将指定的变量导出为全局变量。用户可以同时指.定多个变量名称作为参数(无须使用“$”符号),,变量名之间以空格分隔
如何将自己的变量变成一个环境变量,分为两种方式,永久的跟临时性的,首先进入配置文件 /etc/profile 添加命令
更改之后重新输入命令进行再次读取 source /etc/profile 就可以查看到
永久更改:
例如:进入配置文件,编辑一条命令
查看效果,可以看到是读取到的
临时更改:在命令行直接输入命令
[root@localhost ~]# aa=20
[root@localhost ~]# export aa
[root@localhost ~]# env | grep aa
aa=20
也可以使用这种方式,加入变量的时候就进行赋值
[root@localhost ~]# export bb=10
[root@localhost ~]# bash
[root@localhost ~]# echo $bb
10
[root@localhost ~]#
查看系统当中进入了多少个bash环境
输入命令 echo $SHLVL
退出bash 环境用exit退出即可
3.3 位置变量
位置参数是一种在调用 Shell 程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。 位置参数之间用空格分隔,Shell取第一个位置参数替换程序文件中的 $1,第二个替换 $2 , 依次类推。$0 是一个特殊变量,它的内容是当前这个shell程序的文件名,所以 $0 不是一个位置参数
[root@localhost ~]# vim 1234.sh
#!/bin/bash
echo $0
echo $1
echo $2
:wq
[root@localhost ~]# chmod +x 1234.sh
[root@localhost ~]# ./1234.sh 1 2
./1234.sh
1
2
3.4 预定义变量
预定义变量和环境变量相类似,也是在Shell一开始就定义的变量,不同的是,用户只能根据shell的定义来使用这些变量,所有预定义变量都是由符号“$”和另一个符号组成,常见的Shell预定义变量有以下几种:
种类 | 功能 |
---|---|
$# | 表示命令中位置参数的个数 |
$* | 表示所有位置参数的内容,这些内容当做一个整体 |
$@ | 表示列出所有位置参数,但是以单个的形式的列出 |
$? | 表示前一条命令执行后的返回状态,返回值为0表示执行正确,返回任何非0值表示执行出现异常 |
$0 | 表示当前执行的脚本或者程序的名称 |
$$ | 表示返回当前进程的进程号 |
$! | 返回最后一个后台进程的进程号 |
4. 变量的算数运算
运算符号和数字之间要有空格
算数运算符 | 含义 |
---|---|
+、-、*、/、% | 加法、减法、乘法(注意乘法需要转义)、除法、取余 |
** | 幂运算 |
++、– | 增加、减少 |
!、&&、|| | 逻辑非、逻辑与、逻辑或 |
==、!= | 等于,不等于 |
<、<=、>、>= | 小于、小于等于、大于、大于等于 |
算术运算操作符 | 含义 |
---|---|
(()) | 用于整数运算的常见运算符 |
let | 用于整数运算 |
expr | 可用于整数运算 |
bc | linux里面自带的计算器程序 |
$[ ] | 用于整数运算 |
[root@localhost ~]# expr 1 + 1
2
[root@localhost ~]# expr 1+1
1+1
[root@localhost ~]# expr 2 - 1
1
[root@localhost ~]# expr 2 \* 3
6
[root@localhost ~]# expr 4 / 2
2
[root@localhost ~]# expr 4 % 3
1
$[]和$(()) 必须要和echo在一起用因为他只能运算无法输出结果
[root@localhost ~]# echo $[10*10]
100
[root@localhost ~]# echo $[10%3]
1
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# echo $((10%3))
1
let的运算可以改变变量本身的值,但不显示结果,需要echo,
其他的运算方式可以做运算但不改变变量本身的值
[root@localhost ~]# a=100
[root@localhost ~]# let a++
[root@localhost ~]# echo $a
101
[root@localhost ~]# let a--
[root@localhost ~]# echo $a
100
使用bc进行运算,支持小数运算,scale保留多少小数点的位数
在脚本中不可直接使用否则会进入交互界面,可以用echo结合管道使用
[root@localhost ~]# echo "1.1+2.1" | bc
3.2
[root@localhost ~]# echo "scale=2;10/3" | bc
3.33
[root@localhost ~]# echo "scale=3;10/3" | bc
3.333
[root@localhost ~]# echo "2**8" | bc
(standard_in) 1: syntax error //注意如果是平方,需要使用^符号
[root@localhost ~]# echo "2^8" | bc
256
5. 重定向与管道操作
交互式硬件设备:
标准输入:从该设备接收用户输入的数据
设备文件 /dev/stdin
文件描述编号 0
默认设备 键盘
标准输出:通过该设备向用户输出数据
设备文件:/dev/stdout
文件描述编号 1
默认设备 显示器
标准错误:通过该设备报告执行出错信息
设备文件:/dev/stderr
文件描述编号 2
默认设备 显示器
重定向操作
重定向输入:<
从指定的文件读取数据,而不是从键盘输入
重定向输出:>
将输出结果保存到指定的文件(覆盖原有内容)
重定向输出:>>
将输出结果追加到指定的文件尾部
标准错误输出:2>
将错误信息保存到指定的文件(覆盖原有内容)
标准错误输出:2>>
将错误信息追加到指定的文件中
混合输出:&>
将标准输出、标准错误的内容保存到同一个文件中
[root@localhost ~]# echo 111 > 1.txt
[root@localhost ~]# cat 1.txt
111
[root@localhost ~]# echo 111 >> 1.txt
[root@localhost ~]# cat 1.txt
111
111
[root@localhost ~]# ls xxx
ls: 无法访问xxx: 没有那个文件或目录
[root@localhost ~]# ls xxx > 2.txt
ls: 无法访问xxx: 没有那个文件或目录
[root@localhost ~]# ls xxx >> 2.txt
ls: 无法访问xxx: 没有那个文件或目录
[root@localhost ~]# cat 2.txt
[root@localhost ~]# ls xxx 2>> 2.txt
[root@localhost ~]# cat 2.txt
ls: 无法访问xxx: 没有那个文件或目录
[root@localhost ~]# ls xxxx file.sh
ls: 无法访问xxxx: 没有那个文件或目录
ls: 无法访问file.sh: 没有那个文件或目录
[root@localhost ~]# ls xxxx file.sh > 3.txt
ls: 无法访问xxxx: 没有那个文件或目录
[root@localhost ~]# ls xxxx file.sh 2> 3.txt >4.txt
[root@localhost ~]# cat 4.txt
file.sh
[root@localhost ~]# cat 3.txt
ls: 无法访问xxxx: 没有那个文件或目录
[root@localhost ~]# ls xxxx file.sh &> 5.txt
[root@localhost ~]# cat 5.txt
ls: 无法访问xxxx: 没有那个文件或目录
file.sh
[root@localhost ~]# ls xxxx file.sh &> /dev/null
//相当于一个黑洞,处理各种运行过程,什么都可以放在里面