Shell脚本教程

Shell脚本教程

1. Shell是什么

shell 是一种命令解释器,用户与操作系统内核之间的交互界面,当你登录了Linux后,看到的就是shell

shell其实这个脚本语言是使用C语言开发编写的

而我们通常所讲的bash ,其实是Shell的一种具体实现。在CentOS中,就是用bash 当做解释器的。

可以这样理解,Shell是一门编程语言,但是实现这门编程语言的方式可以有很多种,比如就是bash。

2.Shell脚本是什么?

怎么讲呢,shell脚本就是将多个Linux命令和逻辑循环控制语句,写在一个文件中,然后统一执行这个脚本。

shell脚本以.sh后缀结尾,但是Linux中后缀没什么作用,但是加上后缀可以让人知道你这个文件是干嘛的。

举个脚本的例子...新建一个文件 test.sh ,内容如下。

bash 复制代码
#!/bin/bash
echo "Hello world!!!"
echo "这是一个简单的shell脚本"
echo "#!/bin/bash 是告诉这个代码文件用哪个解释器来解释这些代码"
echo "#!是指定解释器,后面跟的就是具体的解释器路径"
bash 复制代码
# 比如写了一些python 代码,那么就要指定Python的解释器.
#!/usr/bin/python
print ("Hello World")

shell脚本的中的注释是以# 开头的,注释最好使用英文,中文也可以

3.Shell脚本的执行方式

  • bash script.sh 或 sh script.sh 适用文件本身没有执行权限或脚本未指定解释器 (重点推荐)
  • 适用 相对/绝对的路径来执行脚本,需要脚本文件具有可执行权限 例如 ./script.sh
  • source script.sh 或 . script.sh 代表执行的意思,source 就等同于 .

shell 的数据类型默认都是字符串

shell脚本属于弱类型语言,无需声明数据类型,直接定义使用

4.Shell的变量

系统变量

  • 家目录下有自己的全局变量 ~/.bashrc ~/.bash_profile
  • 对每个用户都生效,就需要在root下修改/etc/profile文件

查看系统环境变量的命令

  • set 查看系统所有的系统变量,局部变量
  • env 只显示全局变量
  • declare : 如同set 一样,
  • export 显示和设置环境变量值

撤销环境变量

  • unset 变量名

设置只读变量

  • readonly # readonly age="18"

特殊变量

bash 复制代码
# $0  获取脚本文件的名字 
# $n 获取shell脚本的位置参数  n在 1-9之间,大于9 要写 ${10}
# $# 获取shell脚本执行后面的参数的总个数
# $* 获取shell脚本的所有参数,不加引号等同于$@ 加上引号的作用,接受所有参数为单个字符串 "1 2 3 4 5"
# $@ 不加引号,效果同上,加引号,接受参数为独立的字符串 "1" "2" "3" "4" "5"

特殊状态变量

bash 复制代码
# $? 上一次命令的正确与否返回值,0 True 非0 Flase
# $$ 当前shell脚本的进程号
# $! 上一次后台进程的PID
# $_ 取上次命令传入的最后一个参数
man bash 去查看这些东西

5.Shell子串

bash 的一些内置命令

bash 复制代码
echo
eval
exec
export
read  从控制台读取输入
shift

echo命令

bash 复制代码
# echo 命令式默认换行输出的 echo "你好";echo "hello"
-n  不换行打印输出
-e  识别特殊符号  echo -e "我看你\n挺行"   # 识别\n换行符 
\n 换行
\r 回车
\t 制表格

eval命令

bash 复制代码
一次性执行多个命令
eval ls;cd /etc 

exec命令

bash 复制代码
# 不创建子进程,执行后续命令,且执行完毕后,自动 exit

shell子串的用法

bash 复制代码
name="abcdefg"
${变量} 返回变量值
${#变量} 返回变量长度 字符长度  echo ${#name}  7
${变量:start} 返回变量offset数值之后的字符  offset 是索引,从0开始  ${name:4} efg
${变量:start:length} 返回offset之后的length限制的字符 ${name:2:4} cdef  从2索引开始往后拿4个
${变量#word} 从变量开头删除最短匹配的word子串 ${name#a} bcdefg 匹配a 删调a
${变量##word} 从变量开头 删除最长匹配的word  ${name##a} bcdefg 
${变量%word} 从变量结尾删除最短匹配的word子串
${变量%%word} 从变量结尾删除最长匹配的word子串
${变量/pattern/string} 用string代替第一个匹配的pattern 
${变量//pattern/string} 用string 代替所有的paatern

计算机变量的长度的几种方式

perl 复制代码
# name="nihao180"
echo ${name} | wc -L # -L统计最长的行的长度
# 利用数值计算的命令 expr 计算长度
expr length "${name}"
# 利用awk来统计字符串的长度
echo "${name}" | awk '{print length($0)}' 
# 最快的统计方式
echo "${#name}"

批量文件名替换

bash 复制代码
# 假设 有五个文件分别是:  1_aaa.jpg 2_aaa.jpg 3_aaa.png 4_aaa.jpg 5_aaa.jpg
# 现在,替换 只以.jpg结尾的文件,去掉他们所有的 _aaa
for file_name in `ls *.jpg`;do mv ${file_name} `echo ${file_name//_aaa/}`;done

6. 特殊的Shell扩展变量

bash 复制代码
 这四个扩展变量,都属于对变量的值进行判断、处理
 # 如过 var 变量值为空,返回word字符串,赋给result 变量
 result=${var:-word}
 
 # 如果var为空,则word替代变量值,且返回其值(也就是将word的值返回给 var和result了)
 result=${var:=word}
 
 # 如果var 变量为空,word当做stderr输出,否则输出变量值
 # 用于设置变量为空导致错误时,返回的错误信息
 ${var:?word}   
 
 #如果var变量为空,什么都不做,否则返回word
 result=${var:+word}

删除过期的备份文件

bash 复制代码
find xargs 搜索 且 删除
#删除过期7天的log日志
find ${dir_path:=/data/mysql_log} -name "*.tar.gz" -type f -mtime +7 | xargs rm -rf

7. 父子Shell

  1. source 和 点 , 执行脚本, 只在当前的shell环境中执行生效
  2. 指定 bash sh 解释器运行脚本,是开启了子shell运行的脚本命令
  3. ./script 一般是指定了shebang 也是通过解释器运行,也是开启了子shell运行命令

ps -ef --forest # 以层级关系展示进程的信息

8.内置命令 和 外置命令

内置命令:在系统启动的时候就加载到内存中,常驻内存,执行的效率高,缺点是占用资源

外置命令:系统需要自主的从硬盘中读取程序文件,再读取内存中执行。

内置命令有 cd pwd 等等 ,用type cd 就可以查看 内置命令不会产生子进程执行

外置命令就类似 nginx,我们需要手动去启动nginx这样子 ,外置命令一定会开启子进程执行

bash 复制代码
# 如何查看shell所有的内置命令
compgen -b

9. Shell脚本开发

$()

在括号中执行命令,并拿到命令的执行结果 echo "今天的日期是 $(date)"

9.1 shell数值计算

shell的一些基础命令,只支持整数的运算,不支持小数,bc的命令才支持

用于数值计算的命令

(()) 双小括号 用于数值计算的

bash 复制代码
[root@zabbix-server shell_project]# # 加减乘除
[root@zabbix-server shell_project]# echo $((3+1))
4
[root@zabbix-server shell_project]# echo $((4-1))
3
[root@zabbix-server shell_project]# echo $((4*2))
8
[root@zabbix-server shell_project]# echo $((4/2))
2
[root@zabbix-server shell_project]# echo $((4**3))
64
[root@zabbix-server shell_project]# echo $((7%3))
1

[root@zabbix-server shell_project]# echo ((a=2**3))
-bash: 未预期的符号 `(' 附近有语法错误
[root@zabbix-server shell_project]# #要加$符号取值
[root@zabbix-server shell_project]# echo $((a=2**3))
8
[root@zabbix-server shell_project]# echo a=$((3**4))
a=81

9.2 let 运算命令

bash 复制代码
let等同于(()) 但是(())的效率更高
[root@zabbix-server shell_project]# num=5
[root@zabbix-server shell_project]# let num=num+1
[root@zabbix-server shell_project]# echo $num
6

9.3 expr命令

简单的计算器命令

bash 复制代码
# 它基于空格传入参数,并不是很好用,遇到一些特殊的运算符号,需要加转义才可以
# 基本的加减乘除运算
[root@zabbix-server ~]# expr 5 + 3
8
[root@zabbix-server ~]# expr 5 - 3
2
[root@zabbix-server ~]# expr 5 \* 3
15
[root@zabbix-server ~]# expr 6 \/ 3
2


# 求长度
[root@zabbix-server ~]# expr length 123456
6
[root@zabbix-server ~]# expr length abcsdwdadad
11


# 逻辑判断(0是错,1是正确)
[root@zabbix-server ~]# expr 5 \> 3
1
[root@zabbix-server ~]# expr 5 \< 3
0

9.4 bc命令

命令行计算器

bash 复制代码
[root@zabbix-server shell_project]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
1+1
2
2*2
4
4/2
2
1-1
0
2.2+1.1
3.3

# 结合管道符来计算
[root@zabbix-server shell_project] echo 5*4 | bc
20
[root@zabbix-server shell_project] num=5
[root@zabbix-server shell_project] echo $num*5 | bc
25

# 计算1加到100的值
# 利用bc

$ echo {1..100} # 用来生成1-100的数字,生成的中间有空格,我们把空格全都替换成+号,用tr命令
# tr命令,替换的命令, tr " " "+"  意思是把空格替换成+号

$ echo {1..100} | tr " " "+" | bc
5050
$ seq -s " " 100 | tr " " "+" |bc

10.read命令

read命令参数

  • -p "设置提示信息"
  • -t "设置多长时间未输入的时间,也就是超时时间"
bash 复制代码
read -p "请你输入一个数字:"
read -t 5 -p  "五秒钟输入一个数字,不然就超时不让你输入了:"

11.shell条件测试

shell 提供的条件测试的语法

  • \] 中括号,最常用的

test 命令评估一个表达式,如果为真 ,$? 的值就是0 非零就是假
test 语法大全

bash 复制代码
# 1.关于文件名以及类型检测存在与否
$ -e 该 [文件]是否存在(常用)    test -e /etc/aaa.txt
$ -f 该【文件属性】是否为文件(file)(常用) test -f /etc/bbb
$ -d 该【文件属性】是否为目录 (常用) test -d /home/ccc
$ -S 该【文件属性】是否为一个Socket文件

# 2. 关于文件的权限侦测
$ -r 检测文件是否有可读的属性 test-r ./demo.sh
$ -w 是否可写  
$ -x 是否可执行
$ -u 是否有SUID属性
$ -g 是否有SGID属性
$ -s 是否为非空白文件   # 如果是里面有内容,$?的值是0 如果没内容 就是非零


$ -z # 检测字符串如果是空字符串,则为真,否则为假
$ -n # 检测字符串如果有内容,则为真,否则为假

中括号的使用

中括号和test是一样一样的作用,你想用那个用哪个

注意:在条件测试中使用变量,必须必须必须添加双引号

bash 复制代码
[root@zabbix-server shell_project]# echo `[ -f ./demo.sh  ]` $?
0
[root@zabbix-server shell_project]# file1="hello.txt"
[root@zabbix-server shell_project]# echo `[-f "${file1}"]` $?
bash: [-f: 未找到命令...  # 千万注意,中括号两边必须必须必须有空格
127
[root@zabbix-server shell_project]# echo `[ -f  "${file1}" ]` $?
1

12.shell数值比较

在[] 以及test中使用的比较符号 在(())和[[]]中使用的比较符号 说明
-eq == 或 = 相等,全拼为equal
-ne != 不相等,全拼为not equal
-gt > 大于
-ge >= 大于等于
-lt < 小于
-le <= 小于等于

如果想在[] 中使用 == 或者 != 等等这些比较符号,那么就必须必须必须添加转移符号才可以

bash 复制代码
[ 1 > 2 ] && echo "yes" || echo "no"  #这里的语法错误,因为>号没有被转义,是不对的
[ 1 \> 2 ] && echo "yes" || echo "no" # 这个是对的

# 注意:这里使用!=这个符号,是不需要加转移符号的。

但是哦,我们test中使用这些数学比较符号,是不需要加转义符的...

双中括号和单中括号是一样的,但是但双括号在特殊场景下会有独特的作用,比如支持正则表达式

他两个的其他用法一模一样,最常用单中括号 []

12. 逻辑符号操作

&& 和 -a的作用都一样

|| 和 -o 的作用一样

在[] 以及test中使用的操作符 在(())和[[]]中使用的操作符 说明
-a && and 两端都为真,结果为真
-o || or 或 两端有一个为真,结果为真
! ! not 两端相反 则结果为真

13. 安装LAMP / LNMP脚本开发

bash 复制代码
# 这里不进行真正的安装这两个,只做一个演示
# 我在 /test_script 目录下创建两个演示脚本,LAMP.sh LNMP.sh ,并分别在其中打印一句话,并赋予执行权限。
# 然后在创建一个脚本来调用执行这两个脚本。
cd /test_script
vim LAMP.sh
--------------
#!/bin/bash
echo "正在安装LAMP......."
--------------
vim LNMP.sh
--------------
#!/bin/bash
echo "正在安装LNMP......."
--------------
# 添加执行权限
chmod +x ./*

# 创建另外一个调用的脚本
touch Install.sh
chmod +x Install.sh
vim Install.sh
--------------------------------------------------------------------------------------
#!/bin/bash

# 判断脚本目录是否存在
# 我们优先处理错误的情况
path=/test_script/
[ ! -d "$path" ] && mkdir -p $path

# 提示内容写入
cat <<END
	1.[Install LAMP]
	2.[Install LNMP]
	3.[exit]
END

read -p "please input you want number:" num

# 根据num变量输入进行逻辑处理
expr $num + 1 &> /dev/null
#根据上面的代码的状态码判断用户是否输入的是数字
[ $? -ne 0 ] && {
	echo "你输入的内容必须在1,2,3之间"
	exit 1
}
# 判断输入的数字是否在1,2,3 之间(我们用正则表达式来解决)双括号支持正则表达式
[[ ! "$num" =~ [1-3] ]] && {
	echo "数字必须在1,2,3 之间"
	exit 4
}

# 剩下的情况就是1,2,3 这三个数字的情况了,我们逐个判断
[ "$num" -eq "1" ] && {
	echo "开始安装LAMP.......请等待"
	sleep 2
	# 执行lamp脚本安装
	# 判断文件权限是否有可执行的权限
	[ -x "$path/LAMP.sh" ] || {
		echo "文件不存在,或者没权限"
		exit 1
	}
	$path/LAMP.sh
	exit $?
}

[ "$num" -eq "2" ] && {
	echo "开始安装LNMP.......请等待"
	sleep 2
	# 执行lamp脚本安装
	# 判断文件权限是否有可执行的权限
	[ -x "$path/LNMP.sh" ] || {
		echo "文件不存在,或者没权限"
		exit 1
	}
	$path/LNMP.sh
	exit $?
}

[ "$num" -eq "3" ] && {
	echo "byebye"
	exit
}
--------------------------------------------------------------------------------------
# 然后执行测试即可

14.if语句

14.1 单分支if 语句

bash 复制代码
#!/bin/bash

if [ "1" -eq "1" ];then
	echo "Yes"
fi
# 记得fi闭合

14.2 单/多分支if语句

bash 复制代码
if [ "1" -eq "1" ];then
	echo "Yes"
else
	echo "No"
fi



if [ -f /etc/hosts ];then
	echo "存在"
elif [-d /etc];then
	echo "存在"
else
	echo "不存在"
fi

开发内存监控脚本

bash 复制代码
# 1.检测linux可用内存,如果小于100M,则提示警告发邮件
# 2.并且加入crontab,每三分钟检测一次(定时任务)
bash 复制代码
# 1. 通过free -m 命令取available的值,通过awk命令提取
free -m | awk 'NR==2{print $NF}'

# 2.开发脚本
-----------------------------------------------------------------
#!/bin/bash

FreeMem=`free -m | awk 'NR==2{print $NF}'`
chars="可用内存是: $FreeMem"

if [ "$FreeMem" -lt "100" ];then
	echo "$chars"
	echo "内存不足,及时检查"
fi
-----------------------------------------------------------------

# 设置每三分钟执行一次
# 意思是,*/3 每三分钟
# 用/bin/bash 这个解释器来执行 /test_script/free.sh这个脚本
# 将脚本的输出写入到黑洞文件里去
crontab -e
*/3 * * * *  bin/bash /test_script/free.sh &> /dev/null
相关推荐
wdxylb4 小时前
云原生俱乐部-shell知识点归纳(1)
linux·云原生
飞雪20075 小时前
Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
linux·macos·阿里云·vmware·虚拟机·aliyun·alibaba cloud
路溪非溪5 小时前
关于Linux内核中头文件问题相关总结
linux
Lovyk8 小时前
Linux 正则表达式
linux·运维
Fireworkitte8 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9009 小时前
ubuntu常见问题汇总
linux·ubuntu
ac.char9 小时前
在CentOS系统中查询已删除但仍占用磁盘空间的文件
linux·运维·centos
淮北也生橘1211 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
华强笔记14 小时前
Linux内存管理系统性总结
linux·运维·网络
十五年专注C++开发14 小时前
CMake进阶: CMake Modules---简化CMake配置的利器
linux·c++·windows·cmake·自动化构建