1、shell简述
1.1什么是shell
翻译官功能,与内核进行沟通的应用程序。把代码翻译为二进制,让内核处理,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。
1.2linux的shell:/etc/shells
用户使用命令时,系统会检测这个文件得到内容,命令在里面才可以使用相关命令。
bash(/bin/bash)是目前大多数 Linux 版本采用的默认 Shell。
2、shell脚本
2.1shell脚本文件格式:.sh
2.2运行shell脚本命令:
1.sh first.sh
2.bash first.sh
3.source first.sh
4../first.sh(需要赋予权限)
2.3运行一个简单的shell脚本
vim test.sh //创建一个sh类型的文件
bash test.sh //运行刚才创建的文件
2.3脚本的执行逻辑及执行方式
脚本执行逻辑
1. 顺序执行:程序按从上到下顺序执行
2. 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
3. 循环执行:程序执行过程中需要重复执行多次某段语句
执行方式
指定路径去执行文件(需要有执行权限)
[root@localhost ~]# chmod +x /root/host.sh 加权限
指定相对路径./host.sh
指定绝对路径/root/host.sh
指定解释器去执行(不需要权限)
#!/bin/bash 此处指定的shell为bash,则bash不需要权限也可以执行
source 和 . (不需要权限)
#执行方式三#
source 脚本名(绝对路径)
source /root/host.sh
或者
. /host.sh
2.4Shell脚本错误调试
-
语法错误
会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的。 -
命令错误
默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察。扫描二维码关注公众号,回复: 16561977 查看本文章 -
逻辑错误
只能使用 bash -x 进行排错。
bash -x #模拟执行,可以逐条排错
bash -n #检查语法错误
2.5脚本的优点
1.自动化运维
2.批量化重复操作可以编写脚本结合计划任务自动周期运行
3.减轻管理员工作量
4.提高处理文本文件的速度
5.避免配置出错
2.6运算符
1.加法 +
2.减法 -
3.乘法 \ *
4.除法 /(只会显示整数,除不尽为0)
5.取余 (取模)%
(1) let var=算术表达式
let sum=1+2
sum=1+2
(2) $((var=算术表达式)) 和上面等价
((sum=1+2))
echo $sum
(3) var= $[算术表达式]
(4) var=$((算术表达式))
(5) var=$(expr arg1 arg2 arg3 ...)
(6) var= expr arg1 arg2 arg3 ...
(7) echo '算术表达式' | bc
$[ ]
$(())
$(expr 1 2 3)
#let
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#let z=a+b
[root@localhost ~]#echo $z
3
[root@localhost ~]#let z=$[a-b]
[root@localhost ~]#echo $z
-1
[root@localhost ~]#let z=$((a-b))
[root@localhost ~]#echo $z
-1
#expr
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#expr $a + $b
#加减乘除前后有空格
3
[root@localhost ~]#echo "6*3"|bc
18
echo $[RANDOM%34 +1]
let 支持加加减减 使用较多
[root@localhost ~]#i=1
[root@localhost ~]#let i++
[root@localhost ~]#echo $i
2
[root@localhost ~]#i=1;let i++;echo $i
2
[root@localhost ~]#i=1;let ++i;echo $i
2
[root@localhost ~]#i=100;let j=i++;echo $i $j
101 100
[root@localhost ~]#i=100;let j=++i;echo $i $j
101 101
#i++ 是先赋值给j后再加 ++i是加后再赋值
i++ 是先赋值再加
++i 是加后再赋值
i=$(expr 12 \ * 5 )
i=$((12 * 5))
i=$[12 * 5]
let i=12*5
i++ 相当于 i=$[ $i+1 ]
i-- 相当于 i=$[ $i - 1 ]
i+=2 相当于 i=$[ $i+2 ]
2.7运算法则
1.加法: num1 + num2
2.减法:num1 - num2
3.乘法:num1 \ * num2
4.整除:num1 / num2
5.取余(求模):num1 % num2 (求 num1 除以 num2 的余数)
3、重定向与管道符
3.1重定向
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 2 | 显示器 |
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定的文件读取数据,而不是从键盘输入 |
重定向输出 | 1> | 将输出结果保存到指定的文件(覆盖原有内容) |
>> | 将输出结果追加到指定的文件尾部 | |
标准错误输出 | 2> | 将错误信息保存到指定的文件(覆盖原有内容) |
2>> | 标准错误输出结果追加到指定的文件尾部 | |
混合输出 | &>无论对错都可以重定向 | 将标准输出、标准错误的内容保存到同一个文件中 |
[root@localhost ~]#ls /data /error >all.log 2>&1
#既有错误也有正确 &符号表示分隔符
[root@localhost ~]#cat all.log
ls: 无法访问/error: 没有那个文件或目录
[root@localhost ~]#ls /data /error >all.log 2>1
#如果没有&会生成一个 1文件 将错误导入
3.2管道符
| :主要用在处理文本上,将管道符号“|”左侧的命令输出的结果,作为右侧命令的输入(处理对象),同一行命令中可以使用多个管道。
将user用户的密码改为123123
4、变量
4.1常见的变量类型
自定义变量:由用户自己定义,修改和使用
环境变量:由系统维护,用于设置工作环境
只读变量:只可以读取不可以更改
位置变量:通过命令行给脚本传递参数
预定义变量:Bash中内置的一类变量,不能修改 有些规定好的变量 放在那里让你使用
4.2命名要求
- 区分大小写
- 不能使程序中的保留字和内置变量:如:if, for,hostname 命令 a=
- 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
- 不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
- 大驼峰 StudentFirstName
- 小驼峰 studentFirstName
- 下划线 student_name
弱引用和强引用
"$name " 弱引用,其中的变量引用会被替换为变量值
'$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
4.3 read -p
4.4将局部变量变为全局变量
局部变量:新定义的变量只在当前的shell环境中有效,当进入子程序或新的shell环境中,局部变量将无法再起作用。
全局变量:在新的shell环境中可以继续使用。
通过内部命令export将局部变量为全局变量
格式1:export 变量名
格式2:export 变量名=变量值
#可以使用pstree 查看shell的环境
#输入bash进入子shell
#ctrl+D组合exit 退出子shell
[root@localhost opt]# abc=123
[root@localhost opt]# echo $abc
123
[root@localhost opt]# bash
[root@localhost opt]# echo $abc
为空
[root@localhost opt]# exit
exit
[root@localhost opt]# echo $abc
123
[root@localhost opt]# export abc
#export 变量名 定义全局变量
[root@localhost opt]# bash
[root@localhost opt]# echo $abc
123
4.5环境变量
环境变量由系统提前创建,用来设置用户的工作环境。
env #可以看到当前所有的环境变量
4.5.1常用的环境变量
- $USER 表示用户名称
- $HOME 表示用户的家目录
- $LANG 表示语言和字符集
- $PWD 表示当前所在工作目录
- $PATH 表示可执行用户程序的默认路径
4.5.2环境变量的全局配置文件
#配置文件位置
/etc/profile
##修改此文件,全局生效,可用于长期变更或设置环境变量
4.6只读变量
- 将变量声明为只读(read-only)后,不能再修改变量的值。
readonly 变量名 #将变量声明为只读变量
4.7位置变量
$1, $2, $3, … $n 表示命令行参数的位置值
$1 表示第一个参数,$2 表示第二个参数,以此类推。
当n大于9时,需要加上{ },比如第十个位置,要用 ${10}表示
#以shell脚本为例
#!/bin/bash
echo "$1" #位置1
echo "$2" #位置2
echo "$3" #位置3
echo "${10}" #位置10
echo "$10" #位置1和0
4.8预定义变量
系统帮你定义好了 拿来用就可以了
- $*:表示所有位置参数的内容看成一个整体返回 返回所有
- $@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
- $?:表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
- $#:表示命令行中位置参数的总个数
- $0:表示当前执行的脚本或程序的名称 当前脚本的名字
- $$:当前进程id
- $!: 后台任务最后一个id
5、条件语句
5.1测试
test 测试文件的表达式 是否成立
格式1:test 条件表达式
格式2:[ 条件表达式 ]
注意[]空格,否则会失败
测试 是否成功使用 $? 返回值
[ 操作符 文件或目录 ]
help test
操作符:
-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件
属性测试补充:
-s FILE #是否存在且非空
-t fd #fd 文件描述符是否在某终端已经打开
-N FILE #文件自从上一次被读取之后是否被修改过
-O FILE #当前有效用户是否为文件属主
-G FILE #当前有效用户是否为文件属组
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
[root@localhost ~]# test -e qiuhe.sh &&echo "yes"
yes
&&表示且的意思 前面的表达式成立才会输出yes
5.2比较整数数值
[ 整数1 操作符 整数2 ] 公式
- -eq:第一个数等于(Equal)第二个数
- -ne:第一个数不等于(Not Equal)第二个数
- -gt:第一个数大于(Greater Than)第二个数
- -lt:第一个数小于(Lesser Than)第二个数
- -le:第一个数小于或等于(Lesser or Equal)第二个数
- -ge:第一个数大于或等于(Greater or Equal)第二个数
[ 整数1 操作符 整数2 ]
[root@test1 ~]# a=2 实例
[root@test1 ~]# b=3
[root@test1 ~] [ $a -eq $b ]
[root@test1 ~]# echo $?
1
[root@test1 ~]# [ 2 -le 3 ]
[root@test1 ~]# echo $?
0
5.3字符串比较
常用的测试操作符
- =:字符串内容相同
- !=:字符串内容不同,! 号表示相反的意思
- -z:字符串内容为空
- -n: 字符是否存在
格式
[ 字符串1 = 字符串2 ] 是否相同
[ 字符串1 != 字符串2 ] 是否不相同
[ -z 字符串 ] 是否为空
[ -n 字符串 ] 字符是否存在
[root@localhost data]#str1=wang
[root@localhost data]#str2=zhou
[root@localhost data]#[ $str1 = $str2 ]
[root@localhost data]#echo $?
1
[root@localhost etc]# [ $USER = root ]&& echo true
true
[root@localhost etc]# [ $USER != root ]&& echo true
[root@localhost etc]# read -p "yes/no:" ack
yes/no:
[root@localhost etc]# echo $ack
[root@localhost etc]# [ -z $ack ] && echo true
true
[root@192 ~]# read -p "是否覆盖当前文件 (yes/no)" ACK
是否覆盖当前文件 (yes/no)yes
[root@192 ~]# [ $ACK = "yes" ] && echo "覆盖"
覆盖
[root@192 ~]# read -p "是否覆盖当前文件 (yes/no)" ACK
是否覆盖当前文件 (yes/no)no
[root@192 ~]# [ $ACK = "no" ] && echo "不覆盖"
不覆盖
5.4逻辑测试(短路运算)
格式1:[ 表达式1 ] 操作符 [ 表达式2 ] …
格式2:命令1 操作符 命令2 …
常见条件
- -a或&&:逻辑与,“而且”的意思全真才为真
- -o或||:逻辑或,“或者”的意思一真即为真
- !:逻辑否
- [root@192 ~]# [ ! -d mmm ] && echo “yes”
yes
[root@localhost etc]# [ 4 -lt 5 ]&&echo true || echo false
true
[root@localhost etc]# [ 4 -gt 5 ]&&echo true || echo false
false
[root@localhost etc]# [ 4 -gt 5 ]&& echo true ||echo false
false
|| 只有前面不成立时才会执行后面的操作
合并条件
[root@localhost etc]# [ $a -ne 1 ]&&[ $a != 2 ]
[root@localhost etc]# echo $?
0
[root@localhost etc]# [ $a -ne 1 -a $a != 2 ]
[root@localhost etc]# echo $?
0
[root@localhost etc]# [[ $a -ne 1 && $a != 2 ]]
[root@localhost etc]# echo $?
0
5.5if语句的结构
5.5.1if语句
单分支if语句:
if
then
fi
双分支if语句:
if [ ]
then
else
if
多分支if语句:
if [ ]
then
elif [ ]
then
fi
5.5.2case
语句格式:case 变量 in
模式1)
命令
;;
模式2)
命令
;;
*)
命令
;;
esac
case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[0-9] 指定范围内的任意单个字符
| 或者,如: a|b
5.2.3echo
echo -n 表示不换行输出
echo -e 表示输出转义符
常用的转义符
选项 | 作用 |
---|---|
\r | 光标移至行首,并且不换行 |
\s | 当前shell的名称,如bash |
\t | 插入Tab键,制表符 |
\n | 输出换行 |
\f | 换行,但光标仍停留在原处 |
\ | 表示插入"\"本身转义 |
\b | 表示退格 不显示前一个字符 |
\c | 抑制更多的输出或不换行 |
[root@localhost ky15]#echo -e "12345\b678"
##退格删除前面的字符
1234678
[root@localhost ky15]#echo -e "12345\b\b678"
123678
[root@localhost ky15]#echo -e "12345\b\b\b678"
12678
[root@localhost ky15]#echo -e "12345\b\b\b\b678"
16785
###注意退格键和末尾的字符相关,超过末尾的字符数量 会出bug 了解即可
[root@localhost ky15]#echo -e "12345678\c"
12345678[root@localhost ky15]#echo -e "1234\c5678"
1234[root@localhost ky15]#
###\c 注意 使用在数字中间会把后面内容删除
5.2.4date
date查看当前系统时间
- -d 你描述的日期,显示指定字符串所描述的时间,而非当前时间
- %F 完整日期格式,等价于 %Y-%m-%d
- % T 时间(24小时制)(hh:mm:ss)
[root@localhost ~]# date -d '-1 day' +%F
2021-10-21
[root@localhost ~]# date +%F
2021-08-19
[root@localhost ~]# date -d '1 day ' +%F-%T
2021-08-20-23:28:42
[root@localhost mnt]# date -d "-3 day" 前三天
2021年 08月 18日 星期三 11:30:15 CST
[root@localhost mnt]# date -d "+3 day" 后三天
2021年 08月 18日 星期三 11:30:15 CST
[root@localhost data]#date -d '1 day ' +%F' '%T
2021-10-22 00:45:37
6、现实用例
检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权限