概述
这里只是对shell脚本使用的一个简单介绍,实际上Shell所涉及的东西远远不止如此,但是这些内容能对Shell有一个基础的理解。
脚本解析器
shell常用的解析器主要是bash和sh,可以通过下面命令查看
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
可以通过下面的命令查看默认的解释器
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $SHELL
/bin/bash
创建并执行脚本
shell脚本是以sh为后缀的文件。文件内容就是需要具体执行的脚本命令。
创建脚本
在root目录创建一个名字为hello.sh的脚本
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# touch hello.sh
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# vi hello.sh
## 文件内部添加内容,无需其他内容,执行脚本的时候会直接执行文件内部的语句
echo "helloworld"
启动脚本
- 使用bash启动
使用bash启动脚本需要在命令前添加bash语句
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# bash /root/hello.sh
helloworld
- 直接输入脚本绝对路径执行脚本
这种方式不需要添加
sh
或者bash
命令。直接执行脚本
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./hello.sh
helloworld
++需要注意的++
直接只用./进行访问可能会遇见权限问题
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./hello.sh
-bash: ./hello.sh: Permission denied
此时需要添加权限
chmod 777 variable.sh
变量
自定义变量
我们可以直接通过key=value在linux中设置自己的变量。
设置变量的时候需要注意下面的问题:
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头
- 变量设置对等号附近的空格敏感,所以在设置参数的时候等号两侧不能有空格
- 变量默认的为字符类型,不能进行运算
- 如果变量值中有空格,需要使用单引号或者双引号包裹
- 如果变量值中存在其他变量需要使用双引号。
声明一个变量
这种方式可以声明一个name的变量
echo "赋值新变量:设置变量name为dai"
name=dai
echo $name
脚本输出
赋值新变量:设置变量name为dai
dai
修改一个变量
下面语句尝试修改name变量
echo "重新赋值:修改变量name为dai2"
name=dai2
echo $name
脚本输出
重新赋值:修改变量name为dai2
dai2
删除一个变量
将name变量进行删除
echo "撤销变量:name"
unset name
echo $name
脚本输出
撤销变量:name
声明一个只读的变量
此时尝试删除此变量后此变量依旧可以正常输出
echo "声明只读的变量:name_read"
readonly name_read="readonly"
echo $name_read
unset name_read
echo $name_read
脚本输出
声明只读的变量:name_read
readonly
readonly
输出一个带变量的运算结果
尝试输出一个变量的运算结果,此时使用双引号可以正常输出,而单引号会将变量作为字符串输出
echo "双引号中识别变量"
echo "hello $name_read"
echo "单引号中识别变量"
echo 'hello $name_read'
脚本输出
双引号中识别变量
hello readonly
单引号中识别变量
hello $name_read
将命令结果赋值给变量
此方法可以将linux中命令的结果赋值给变量,下面使用命令
或者$(命令)都是可以的
echo "将一个命令结果给其他变量方法1"
name1=`date`
echo $name1
echo "将一个命令结果给其他变量方法2"
name2=$(date)
echo $name2
脚本输出
将一个命令结果给其他变量方法1
Wed Oct 7 13:33:16 CST 2020
将一个命令结果给其他变量方法2
Wed Oct 7 13:33:16 CST 2020
脚本中变量的范围
脚本中声明变量在控制台中尝试获取
现在最开始的hello.sh修改成下面样子,对一个this_date变量进行赋值。
echo "输出this_date"
echo $this_date
this_date=`date`
echo "设置完后输出this_date"
echo $this_date
此时执行后可以看到结果已经声明的变量内容。但是后续尝试在控制台中获取此变量却没有获取到结果,可以发现脚本中声明的变量并没有传递到控制台中
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./hello.sh
输出this_date
设置完后输出this_date
Wed Oct 7 13:48:39 CST 2020
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $this_date
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]#
在控制台中声明变量,脚本中尝试获取
此时可以发现在外部声明的变量在脚本中同样无法获取。
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# this_date=`date`
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $this_date
Wed Oct 7 13:53:06 CST 2020
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./hello.sh
输出this_date
设置完后输出this_date
Wed Oct 7 13:53:23 CST 2020
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]#
这是因为上面脚本执行是当前shell中打开一个子shell来执行脚本内容,当脚本内容结束,则子shell关闭,回到父shell中。如在子shell中设置的当前变量,不做特殊通道处理的话,父shell是不可见的。
将自定义变量设置为全局变量
我们可以将自定义变量设置为全局变量,这边其他的shell脚本也可以使用。
这样操作需要将之前的脚本最后添加下面内容:
export this_date
此时再进行操作就可以获得结果
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./hello.sh
输出this_date
设置完后输出this_date
Wed Oct 7 13:58:17 CST 2020
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $this_date
Wed Oct 7 13:53:06 CST 2020
当然也可以尝试修改
/etc/profile
文件通过添加export key=value
来设置变量为系统变量。不过不要忘了最后执行source /etc/profile
命令
脚本参数变量
当脚本存在输入参数的时候,可以使用n 、 n、n、#、∗ 、 *、∗、@来获取参数的内容
$n
可以用$n来表示哪个参数。0 : 为 脚 本 名 称 ; 1 − n 表 示 第 几 个 参 数 , 其 中 1 − 9 表 示 为 0:为脚本名称;1-n表示第几个参数,其中1-9表示为0:为脚本名称;1−n表示第几个参数,其中1−9表示为n,10以上需要包裹大括号${n}
$#
用来获取参数个数
$*
命令行中所有的参数,$*把所有的参数看成一个整体
$@
代表命令行中所有的参数,$@把每个参数区分对待
实例
现在创建一个param.sh的脚本内容如下
echo "$0 $1 $2"
echo $#
echo $*
echo $@
其输出内容
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./param.sh param1 param2
./param.sh param1 param2
2
param1 param2
param1 param2
命令执行结果变量
$?
变量可以证明上一个命令是否正确执行。如果为0在证明执行正确,否则则证明执行出现了问题
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./param.sh param1 param2
./param.sh param1 param2
2
param1 param2
param1 param2
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $?
0
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# asdad
-bash: asdad: command not found
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $?
127
计算
计算的语法
- *号需要转义为*
- 运算指的都是整数的运算
- 运算以expr开始,符号间需要空格
运算符号
符号 | 作用 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余 |
嵌套运算
当存在(a + b) * C这种多个运算嵌套的时候下面两种方式都能实现结果
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# expr `expr 1 + 2` \* 3
9
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# rest=$[(1+2)*3]
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# echo $rest
9
判断
判断语句的语法
## 注意前后要有空格
[ 判断语句 ]
判断条件
符号 | 作用 |
---|---|
= | 字符串比较 |
-lt | 小于 |
-le | 小于等于 |
-eq | 等于 |
-gt | 大于 |
-ge | 大于等于 |
-ne | 不等于 |
-r | 有读的权限 |
-w | 有写的权限 |
-x | 有执行的权限 |
-f | 文件存在并且是一个常规的文件 |
-e | 文件存在 |
-d | 文件存在并是一个目录 |
-s | 文件存在且不为空 |
-L | 文件存在且是一个链接 |
使用示例
使用下面方式可以实现结果的输出
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# [ 23 -ge 26 ] && echo ture || echo false
false
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# [ -w hello.sh ] && echo ture || echo false
ture
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# [ -d hello.sh ] && echo ture || echo false
false
流程控制
if
shell 中的if流程格式为下面格式,最后以fi结束。课条件判断一样[]和条件公式需要空格分隔,而if后面也需要空格分隔
if [ 条件判断式 ]
then
逻辑1
elif 条件判断式
then
逻辑2
else
逻辑3
fi
示例
创建下面的一个脚本用来表示if的使用方式
if [ $1 -eq 1 ] ;
then
echo "输入逻辑1"
elif [ $1 -eq 2 ] ;
then
echo "输入逻辑2"
elif [ $1 -eq 3 ] ;
then
echo "输入逻辑3"
else echo "未知逻辑"
fi
返回内容
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 1
输入逻辑1
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 2
输入逻辑2
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 3
输入逻辑3
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 7
未知逻辑
++需要注意++
和上面使用简单逻辑的示例不同,这里涉及多行判断,此时可能会遇见换行符的问题,
通过vim编辑脚本,在命令行模式下输入:set ff
如果结果为fileformat=dos
则需要手动输入置:set ff=unix
来设置文件对应系统
case
基本语法
case逻辑以case开始以esac结束
case $变量 in
值1)
程序1 ;;
值2)
程序2 ;;
值3)
程序3 ;;
*)
其他 ;;
esac
示例
将上面if的逻辑改为case后脚本内容如下
case $1 in
1)
echo "case输入逻辑1" ;;
2)
echo "case输入逻辑2" ;;
3)
echo "case输入逻辑3" ;;
*)
echo "case未知逻辑" ;;
esac
输出内容如下
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 8
case未知逻辑
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 1
case输入逻辑1
for
基本语法
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
示例
上面内容可以使用一个简单的i循环来实现其效果
for((i=0;i<=10;i++))
do
echo $i
done
最终输出内容
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh
0
1
2
3
4
5
6
7
8
9
10
for 还能实现一种类似foreach的语法
for (变量 in 值1 值2 值3);
do 程序;
done
示例
将上面语法改造下,用来循环输入参数
for i in $*
do
echo $i
done
++注意++
使用 for i in "$*"
的时候整个参数会被看成一个整体,而只循环1次
执行后结果
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 1 3 5 6
1
3
5
6
while
基础语法
# 第一种
while [ 条件判断式 ]
do
程序
done
# 第二种
while((表达式))
do
程序
done
示例
将上面的i循环改造为while格式
i=0
while [ $i -le 10 ]
do
echo $i
i=$[$i+1]
done
最终输出的内容和使用i循环是一致的
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh
0
1
2
3
4
5
6
7
8
9
10
函数
自定义函数
shell中我们可以使用函数来实现一些复杂的逻辑,这里只介绍自定义函数的内容
++注意内容++
- 函数需要提前声明,shell脚本是逐行运行。不会像其它语言一样先编译。
- 函数返回值,只能通过$?系统变量获得
函数声明的格式
function funname()
{
Action;
[return int;]
}
示例
创建一个汇总输入参数和的函数
sum_param=0
function rest() {
for i in $*
do
echo $i
sum_param=$[$sum_param + $i]
done
}
rest $*
echo "输入参数和为:$sum_param"
最终返回结果
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh 2 4 5
2
4
5
11
在脚本中提供用户输入
shell提供的输入语法
read -t 等待时间 -p "提示语句" 变量名称
示例
read -t 5 -p "请在5秒钟内输入一个数字" NUM
echo "输入的数字为:$NUM"
脚本执行的结果
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]# ./test.sh
请在5秒钟内输入一个数字8
输入的数字为:8
[root@iZbp1buyhgwtrw6hrp2ugjZ ~]#
个人水平有限,上面的内容可能存在没有描述清楚或者错误的地方,假如开发同学发现了,请及时告知,我会第一时间修改相关内容。假如我的这篇内容对你有任何帮助的话,麻烦给我点一个赞。你的点赞就是我前进的动力