一、Shell 是什么
Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,用户可以用 Shell 来启动、挂起、停止甚至是编写一些程序。
1、Shell 能做些什么
- Linux 运维工程师在进行服务器集群管理时,需要编写 shell 程序来进行服务器管理。
- 对于 JavaEE 和 Python 程序员来说,可以编写一些 shell 脚本进行程序或者服务器的维护。比如:编写一个定时备份数据库的脚本。
- 对于大数据程序员来说,需要编写 shell 程序来管理集群。
二、第一个 shell 脚本
1、脚本格式要求
- 脚本以
#!/bin/bash
开头。 - 脚本后缀为 .sh。
- 脚本需要有可执行权限。
2、输出 hello world
#!/bin/bash
echo "hello world"
3、常用执行方式
方式一
输入脚本的绝对路径或相对路径执行。首先属于 xx.sh 脚本 +x(可执行)权限,然后执行脚本。
方式二
不赋予脚本 +x 权限,直接使用 sh + 脚本执行。
4、特殊字符的应用
美元符号($)
美元符号“$”表示变量替换,即用其后指定的变量的值来代替变量。
单引号(')
由单引号括起来的字符都作为普通字符出现。
双引号(")
由双引号括起来的字符,除 $、倒引号、反斜线仍保留其特殊功能外,其余字符均作为普通字符对待。
倒引号(`)
由倒引号括起来的字符串被 shell 解释为命令行,在执行时,shell 会先执行该命令行,并以它的标准输出结果取代整个倒引号部分。
反斜线(\)
反斜线“\”为转义字符,转义字符告诉 shell 不要对其后面的那个字符进行特殊处理,只是当做普通字符。
5、注释
单行注释
以 # 开头的行就是注释,会被解释器忽略。
#!/bin/bash
# 第一个 shell 程序
echo "hello world"
多行注释
多行注释使用以下格式:
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
EOF 也可以使用其他符号:
:<<'
注释内容...
注释内容...
注释内容...
'
:<<!
注释内容...
注释内容...
注释内容...
!
三、Shell 的变量
- shell 中的变量分为,系统变量和用户自定义变量。
- 系统变量:
$HOME
、$PWD
等等。 - 显示当前 shell 中的所有变量:set。
1、变量的定义
基本语法
- 定义变量:变量 = 值。
- 撤销变量:unset 变量。
- 声明静态变量:readonly 变量,注意:静态变量不能 unset。
命名规则
- 变量名可以由字母、数字和下划线组成,但是不能以数字开头。
- 变量名中间不能有空格,不能使用标点符号和关键字。
- 变量名称一般习惯为大写。
将命令返回值赋给变量
- A=`ls -la` 反引号,运行里面的命令,并把结果返回给变量 A。
- A=$(ls -la) 等价于反引号。
快速入门
定义变量 A 并输出。
#!/bin/bash
A=3
echo $A
获取命令返回结果并输出。
#!/bin/bash
A=`ls -l`
echo $A
2、设置环境变量
基本语法
- export 变量名=变量值(将 shell 变量输出为环境变量)
- source 配置文件(让修改后的配置信息立即生效)
- echo $变量名(查询环境变量的值)
自定义环境变量
- 打开 /etc/profile 文件;
- 使用 export 命令在文件末尾定义环境变量;
- 使用 source 刷新配置文件;
- 使用 echo 查看环境变量的值或使用 env 查看所有环境变量。
打开 /etc/profile 文件
vi /etc/profile
使用 export 命令在文件末尾定义环境变量
export A=zyx.sh
使用 source 刷新配置文件
source /etc/profile
使用 echo 查看环境变量的值
echo $A
3、位置参数变量
如果希望获取到命令行的参数信息,就可以使用到位置参数变量。比如:./myshell.sh 100 200
,这就是一个执行 shell 的命令行,可以在 shell 脚本中获取到参数信息。
基本语法
$n
:n 为数字,$0
代表命令本身;$1-$9
代表第一到第九个参数;十以上的参数需要用大括号包含,如:${10}
;$*
:代表命令行中所有的参数,$*
把所有的参数看成一个整体;$@
:代表命令行中所有的参数,不过$@
把每个参数区分对待;$#
:代表命令行中所有参数的个数。
实例
#!/bin/bash
echo $0
echo $1
echo $*
echo $@
echo $#
输出结果。
[root@localhost shell]# ./zyx.sh a b
./zyx.sh
a
a b
a b
2
4、预定义变量
预定义变量就是 shell 设计者事先定义好的变量,可以直接在 shell 脚本中使用。
基本语法
$$
:当前进程的进程号(PID)。$!
:后台运行的最后一个进程的进程号(PID)。$?
:最后一次执行命令的状态。如果值为 0,证明上一个命令正确执行,如果为 非 0(具体是哪个数,由命令自己决定),则证明上一个命令没执行成功。
5、数组
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:
array_name=(value1 value2 ... valuen)
也可以使用下标来定义数组:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
获取数组长度,利用 @
或 *
,可以将数组扩展成列表,然后使用 #
来获取数组元素的个数,格式如下:
${#array_name[@]}
${#array_name[*]}
实例
定义数组并输出其中的值。
#!/bin/bash
my_array=(A B "C" D)
echo "第一个元素为: ${my_array[0]}"
my_array[0]=1
echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"
for i in ${my_array[*]}
do
echo "$i"
done
echo "数组的长度为:${#my_array[@]}"
四、运算符
使用运算符在 shell 中进行运算操作。
基本语法
- $((运算式));
- $[运算式];
- expr m + n (注意 expr 运算符间要有空格);
- expr
-
、\*
、/
、%
;减、乘、除、取余。
实例
计算 (2+3)*4 的值。
#!/bin/bash
echo $(((2+3)*4))
echo $[(2+3)*4]
expr \( 2 + 3 \) \* 4
求出命令行的两个参数的和。
#!/bin/bash
echo $[$1+$2]
输出结果。
[root@localhost shell]# ./zyx.sh 1 2
3
五、条件判断
1、判断语句
基本语法
condition 前后要有空格,非空返回 true,可以使用$?验证( 0 为true,>1 为 false)
[ condition ] && 为true时执行 || 为false时执行
实例
判断指定文件是否存在,不存在则创建
[ ] && echo ok || echo notok
2、判断条件
两个整数的比较
- =:字符串比较
- -lt:小于
- -le:小于等于
- -eq:等于
- -gt:大于
- -ge:大于等于
- -ne:不等于
按照文件的权限进行判断
- -r:有读的权限
- -w:有写的权限
- -x:有执行的权限
按照文件类型进行判断
- -f:文件存在并且是一个常规的文件
- -e:文件存在
- -d:文件存在并且是目录
六、流程控制
1、if 语句
基本语法
下面是 if 语句的语法。注意:[ 判断条件 ],中括号和判断条件之前必须有空格。
if [ 判断条件 ]
then
程序
elif [ 判断条件 ]
then
程序
else
程序
fi
实例
"1"是否等于"ok"
if [ "1" = "ok" ]
then
echo "equal"
fi
23是否大于等于22
if [ 23 -ge 22 ]
then
echo "大于"
fi
判断 /root/install.log 文件是否存在
if [ -e /root/zyx/zyx.sh ]
then
echo "存在"
fi
编写一个 shell 程序,如果输入的参数,大于等于 60,则输出"及格了",如果小于 60,则输出"不及格"。
if [ $1 -ge 60 ]
then
echo "及格"
else
echo "不及格"
fi
2、case 语句
基本语法
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
...省略其他分支
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
实例
当命令参数行是 1 时,输出“周一”;是 2 时,就输出“周二”;其他情况输出“other”。
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "other"
;;
esac
3、for 循环
语法1
for 变量 in 值1 值2 值3
do
程序
done
语法2
for((初始值;循环条件;变量变化))
do
程序
done
实例
打印命令行输入的参数。
for i in "$*"
do
echo "the num is $i"
done
for i in "$@"
do
echo "the num is $i"
done
输出 1 加到 100 的和。
sum=0
for ((i=0;i<=100;i++))
do
sum=$[$sum+$i]
done
echo "sum=$sum"
4、while 循环
语法
while [ 条件判断 ]
do
程序
done
实例
从命令行输入一个数 n ,统计 1+...+n 的值是多少。
um=0
i=0
while [ $i -le $1 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo "sum=$sum"
七、read 读取控制台输入
使用 read 可以读取控制台输入的数据,类似于 Java 的 Scanner。
语法
read 选项 变量名
- -p:指定读取值时的提示符;
- -t:指定读取值时等待的时间(秒),如果没有在指定的时间内输入,那就不再等待。
实例
读取控制台输入的值。
read -p "请给i赋值" i
echo "i的初值为:$i"
读取控制台输入的值,必须在 10 秒内输入。
read -t 10 -p "为i赋初值" i
八、函数
shell 编程和其他编程语言一样,有系统函数,也可以自定义函数。
1、系统函数
1)basename 的用法
basename 会删掉 string 中 / 的所有前缀包括最后一个 / 字符,然后将字符串显示出来,常用于获取文件名。suffix 为后缀,如果 suffix 被指定了,basename 会将 string 中的 suffix 去掉。
basename [string] [suffix]
返回 /home/aaa/test.txt 的 test.txt 部分
2)dirname 的用法
dirname 返回 string 最后 / 的前面的部分,常用于返回路径。
dirname [string]
返回 /home/aaa/test.txt 的 /home/aaa
2、自定义函数
基本语法
调用函数,直接写函数名:funname。函数参数的获取方式和获取位置参数的方式一样。
[function] funname [()]
{
Action;
[return value]
}
如果函数有返回值,则在调用该函数后通过 $?
来获得。$?
仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 $?
获得。
注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。
实例
接收三个参数,返回后两个参数的和。
#!/bin/bash
function getSum(){
sum=$[$1+$2]
return $sum
}
echo "第二个参数为:$2"
echo "第三个参数为:$3"
getSum $2 $3
echo "和 getSum $?"
九、自动备份数据库
1、需求分析
- 每天凌晨 2 点备份数据库。
- 备份时,给出响应的提示信息
- 备份成功后将备份文件以时间命名并打包成 .tar.gz 的形式
- 在备份时,检查是否有 2 月前备份的数据库文件,如果有则删除。
2、代码实现
#!/bin/bash
# 备份的路径
path=/data/mysql
# 获取当前时间
date=`date +"%F"`
# 主机
host=localhost
# 用户
user=root
# 密码
password=root
# 备份的数据库名
dataName=(A B)
echo "开始备份数据库,时间:`date "+%F %T"`,备份路径:$path"
# 判断目录是否存在
[ ! -d "$path/$date" ] && mkdir -p "$path/$date"
# 开始备份
for i in ${dataName[@]}
do
tmp="mysqldump -u${user} -p${password} --host=${host} $i > /sql/$i.sql"
docker exec mysql /bin/bash -c "$tmp"
echo "$i 备份完成"
done
echo "sql文件备份完成"
# 备份完将sql移动到指定目录中
mv /data/docker/mysql/* $path/$date
# 打包
tar -zcvPf $path/$date.tar.gz $path/$date
echo "sql文件打包完成"
# 删除原文件
rm -rf $path/$date
# 删除30天前的备份文件
find $path -mtime +30 -name "*.tar.gz" -exec rm -rf {} \;
echo "已删除30天前的备份文件"
echo "============================"
3、定义定时器
Linux 内置的 cron 进程能帮我们实现这些需求,cron 搭配 shell 脚本,非常复杂的指令也没有问题。定时器的日志文件: /var/spool/mail/root。
语法规则:
crontab [-u username] # 省略用户表表示操作当前用户的crontab
-e (编辑工作表)
-l (列出工作表里的命令)
-r (删除工作作)
crontab -e 进入当前用户的工作表编辑,是常见的 vim 界面。每行是一条命令。crontab 的命令构成为
时间+动作,其时间有分、时、日、月、周五种,操作符有:
- *:取值范围内的所有数字;
- /:每过多少个数字;
- -:从X到Z;
- ,:散列数字。
例如:
* * * * * 每1分钟执行一次
30 21 * * * 每晚的21:30
3,15 8-11 * * * 在上午8点到11点的第3和第15分钟执行
标题:Shell 编程
作者:Yi-Xing
地址:http://47.94.239.232:10014/articles/2020/10/21/1603249619063.html
博客中若有不恰当的地方,请您一定要告诉我。前路崎岖,望我们可以互相帮助,并肩前行!