shell解释器
linux中有很多的shell解释器,默认使用为bash,路径为/bin/bash,其他还有很多种shell,在etc/shells中可以查看系统中所有的shell解释器
[root@localhost bin]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
/bin/ksh
/bin/rksh
可以通过直接输入解释器的名称来打开不同的解释器使用,再通过exit退出当前解释器,回到上一级解释器
[root@localhost bin]# ksh
# tcsh
[root@localhost /bin]# exit
exit
# exit
需要其他解释器的时候也可以用之前的yum命令直接安装,bash解释器有很多优点,比如他支持用tab智能补充命令,支持管道(|)和重定向(> >>),支持查询历史命令并且直接使用历史命令等等
shell脚本基础格式及使用
shell脚本基础格式
shell脚本方便我们重复多次相同或者相似的操作,一般存于/opt中,有一定的格式要求
[root@localhost bin]# cd /opt
[root@localhost opt]# vim ty1.sh
//先进入目录/opt,然后使用vim编辑创建一个.sh文件编辑
#!/bin/bash
#这是一个shell脚本,用来打印helloworld
echo helloworld
//进入编辑模式后,输入以上内容,第一行为解释器及路径,第二行为注释,第三行为脚本执行内容,输入完成保存退出
基础脚本就编写完了,然后就是执行脚本的几种方式
方式1,赋予权限后直接使用路径执行
赋予该脚本执行的权限(+x),并且直接输入路径即可运行
[root@localhost opt]# cat ty1.sh
#!/bin/bash
#这是一个shell脚本,用来打印helloworld
echo helloworld
[root@localhost opt]# chmod +x ty1.sh
[root@localhost opt]# ./ty1.sh
helloworld
方式2,使用指定解释器运行
基础格式:解释器名 脚本路径
[root@localhost opt]# sh ty1.sh
helloworld
这种方式其实是创建了一个解释器的子进程,在子进程中运行,我们所用的bash解释器为主进程,所以一旦脚本中有了打开目录类似的操作,就会导致操作无法正常运行,因为其打开文件也在子程序中,而非主程序中
[root@localhost opt]# cat ty2.sh
#!/bin/bash
#这是一个创建并打开目录acc的脚本
mkdir acc
cd acc
[root@localhost opt]# sh ty2.sh
[root@localhost opt]# find acc
acc
这里目录acc已经被脚本创建成功,但是cd acc命令没有成功运作,当前目录仍旧在/opt,因为这一步在子进程sh中完成并且关闭,主进程就无法进入该目录,解决这一问题就要用到source
方式3,source命令
基础格式:source 脚本路径
和方式2不同,source实际上使用默认的解释器,不会开启子进程,所以就可以解决方式2中的问题,接着上面的代码
[root@localhost opt]# rm acc -rf
[root@localhost opt]# source ty2.sh
[root@localhost acc]#
先删除刚才创建的文件acc,然后使用source运行代码,cd acc这一步就成功执行了,当前目录进入了acc中
shell变量
自定义变量
变量命名的时候有一些规则,命名时只能使用英文,数字,下划线,并且首字符不能用数字开头,且等号左右两侧一格位置不能有空格,不能使用系统的关键字(ls,cd等等)来命名,且变量的值如果有空格,那么就需要用引号括起来(a="a b"),单双引号区别在界定符位置一起总结
//错误的变量命名
[root@localhost opt]# a = 12
bash: a: 未找到命令...
[root@localhost opt]# 22a=12
bash: 22a=12: 未找到命令...
[root@localhost opt]# a=a b
bash: b: 未找到命令...
一个变量设置好之后,就是调用这个变量的值,使用符号$,如果在变量后面需要紧接其他字母或数字等干扰因素,将变量用[]括起来,示例:
[root@localhost opt]# a=998
[root@localhost opt]# echo $a
998
[root@localhost opt]# echo $acm
[root@localhost opt]# echo $[a]cm
998cm
使用uset 变量名,可以直接删除指定变量
环境变量
环境变量为系统已经定义好的全局变量,使用的时候直接调用即可,常用的有
-
USER 当前用户名
-
HOME 当前用户家目录
-
UID 当前用户UID
-
SHELL 当前用户解释器
-
PWD 当前位置
-
PS1 一级提示符
-
PS2 二级提示符
这里一级提示符与二级提示符:
[root@localhost opt]# PS1=tishifu
tishifuls
a acc helloworld.sh ty2.sh
tishifu
一级提示符为每次输入代码前的那一排显示的内容,这里将一级提示符改为tishifu之后,可以看到ls仍旧可以正常运行。而当一行的长度不足以装下全部代码的时候,我们可以输入\后回车,会切换至下一行输入,最前面的>即为二级提示符
[root@localhost /]# cd \
> /opt
[root@localhost opt]#
位置变量
$n为第n个参数值,$*为命令行中所有参数,把所有参数看做一个整体,$@则把所有参数看做单个个体对待,$#为参数个数,$$为随机进程号,$?判断上一步是否执行成功,成功为0,非0为失败
[root@localhost opt]# cat ty3.sh
#!/bin/bash
#这是一个位置变量参考脚本
echo $1
echo $3
echo $6
echo $*
echo $$
echo $#
echo $?
[root@localhost opt]# source ty3.sh 1 2 3 4 5 6 7 8 9
1
3
6
1 2 3 4 5 6 7 8 9
35691
9
0
界定符
常见的三种界定符,双引号,单引号,反撇号
单引号''会把所有的字符全部当做普通字符处理
[root@localhost opt]# a=10
[root@localhost opt]# echo $a
10
[root@localhost opt]# echo '$a'
$a
双引号""用于界定范围,会将特殊字符按照特殊字符处理
[root@localhost opt]# echo $adddddddd$a
10
[root@localhost opt]# echo "$a"dddddddd$a
10dddddddd10
反撇号``会获取后面命令的结果而非命令本身,也可以用$()代替反撇号
[root@localhost opt]# a=date
[root@localhost opt]# echo $a
date
[root@localhost opt]# a=`date`
[root@localhost opt]# echo $a
2021年 09月 25日 星期六 10:04:36 CST
[root@localhost opt]# a=$(date)
[root@localhost opt]# echo $a
2021年 09月 25日 星期六 10:05:15 CST
read指令
read指令可以让脚本获得用户处的输入,让脚本成为交互式
基础格式:read -p "显示的内容" 存到哪个变量中
示例:在.sh脚本中编写如下代码
#!/bin/bash
#创建账号并配置密码
read -p "请输入要创建的账号名" username
stty -echo
read -p "请输入密码" passwd
stty echo
useradd $username
echo $passwd | passwd --stdin $username
其中,stty -echo可以让用户输入的内容无法在屏幕上显示出来,用于保护密码隐私,输入完密码后styy echo可以让内容重新显示
[root@localhost abc]# source zhanghao.sh
请输入要创建的账号名bc
请输入密码更改用户 bc 的密码 。
passwd:所有的身份验证令牌已经成功更新。
运行结果如上,交互处有两处,为输入账号和密码的部分,且密码也如预期被隐藏
shell中的运算
expr命令
expr命令可实现基础整数之间的加减乘除,使用时运算符两边必须有空格
[root@localhost abc]# expr 9 + 3
12
[root@localhost abc]# expr 9 / 3
3
[root@localhost abc]# expr 9 '*' 3
27
[root@localhost abc]# expr 9 % 2
1
需要注意,expr结果会自动输出,只能输出整数,且使用乘法时要加上单引号
$[]形式
$[]形式不会自己输出结果,需要结合echo使用
[root@localhost abc]# echo $[ 9 + 3 ]
12
[root@localhost abc]# echo $[ 9 * 3 ]
27
let指令
let用于变量的创建而非结果的输出
[root@localhost abc]# let a=5+3
[root@localhost abc]# echo $a
8
[root@localhost abc]# let a++
[root@localhost abc]# echo $a
9
数字关系运算符
顾名思义,其只适用于数字或者参数为数字的变量之间的大小关系比对
-eq 相等输出真
-ne 不相等输出真
-gt 左大右输出真
-lt 左小右输出真
-ge 左大于等于右输出真
-le 左小于等于右输出真
使用示例:
[root@localhost abc]# a=1
[root@localhost abc]# b=1
[root@localhost abc]# [ $a -eq $b ]
[root@localhost abc]# echo $?
0
[root@localhost abc]# a=2
[root@localhost abc]# [ $a -eq $b ]
[root@localhost abc]# echo $?
1
逻辑运算符
!取反,[!false]则为true
-o 或运算,[$a -eq $b -o $c -eq $d],有一个表达式为真则返回真
-a 与运算,[$a -eq $b -a $c -eq $d],全真返回真
逻辑与:[ a -eq a ] && ls,前为真,执行ls
[ a -eq b ] && ls,前为假,不执行ls
逻辑或:[ a -eq a ] || ls,前为真,不执行ls
[ a -eq b ] || ls,前为假,执行ls
字符串运算符
字符串运算符作用对象为字符串
== 检测$a,$b是否相等,相等返回真 [ $a == $b ]
!= 检测$a,$b是否相等,不等返回真
-z 检测字符串长度是否为0,为0返回真 [ -z $a ]
-n 检测字符串长度是否为0,不为0返回真
str 检测字符串是否为空,不为空返回真
检测返回值仍然用前面的echo $?方法
shell脚本中的if,for,while
if
if的基础语法为
if 条件;then
满足条件就执行指令1
elif 条件;then
满足条件就执行指令2
else
其他情况下执行指令
fi
直接看例子来得快:
[root@localhost abc]# cat panduan.sh
#!/bin/bash
#用户名判断
read -p "请输入要判断的用户名" username
num=$(cat /etc/passwd | grep $username | wc -l)
if [ $num == 0 ];then
echo "对不起,该用户不在系统中"
else
echo "该用户在系统中"
fi
这是一个判断用户名是否在本系统中的if代码,结合了前面的read指令和运算关系,其中管道| wc -l 作用为输出满足条件的数量
[root@localhost abc]# cat if.sh
#!/bin/bash
#if分支
read -p "请输入我的成绩" chengji
if [ $chengji -le 100 ] && [ $chengji -ge 60 ];then
echo "考的不错啊"
elif [ $chengji -lt 60 ] && [ $chengji -ge 0 ];then
echo "这次不太行啊"
else
echo "?你是怎么做到的?"
fi
这是一个if多分支的判断成绩,按照输入成绩的不同输出不同的结果
for
for的基础语法为
for 变量名称 in 值1 值2 值3
do
执行内容
done
一样直接上例子:
[root@localhost abc]# cat xunhuan2.sh
#!/bin/bash
#这是一个简单循环
for i in 1 2 3
do
echo "这是第$i次循环了"
done
[root@localhost abc]# source xunhuan2.sh
这是第1次循环了
这是第2次循环了
这是第3次循环了
for循环的数值位置,可以填写其他内容,只是代表此次循环i为多少
[root@localhost abc]# cat xunhuan3.sh
#!/bin/bash
#这是一个简单循环
for i in abc cdc weq
do
echo "这次循环内容为$i"
done
[root@localhost abc]# source xunhuan3.sh
这次循环内容为abc
这次循环内容为cdc
这次循环内容为weq
当循环次数要求特别多的时候,可以采用省略号的方式来决定次数
[root@localhost abc]# cat xunhuan4.sh
#!/bin/bash
#这是一个简单循环
for i in {1..10}
do
echo "这是第$i次循环了"
done
[root@localhost abc]# source xunhuan4.sh
这是第1次循环了
这是第2次循环了
这是第3次循环了
这是第4次循环了
这是第5次循环了
这是第6次循环了
这是第7次循环了
这是第8次循环了
这是第9次循环了
这是第10次循环了
最终你还可以结合外部输入来做到想循环几次就循环几次,使用seq命令
[root@localhost abc]# cat xunhuan.sh
#!/bin/bash
#该代码为循环的示例
read -p "请输入想要循环多少次" cishu
for i in $(seq $cishu)
do
echo "这是第$i次循环"
done
[root@localhost abc]# source xunhuan.sh
请输入想要循环多少次5
这是第1次循环
这是第2次循环
这是第3次循环
这是第4次循环
这是第5次循环
while
while的基础语法为
while 条件为真
do
执行相应指令
done
也直接上列子吧,RANDOM可以生成一个随机数
[root@localhost abc]# echo $RANDOM
4520
[root@localhost abc]# echo $RANDOM
27502
[root@localhost abc]# echo $RANDOM
19444
那么就可以编写一个猜数字小游戏,利用while让他一直循环,我们一直猜,再利用前面shell中的运算和if做到比大小提示,猜中就break
[root@localhost abc]# cat cai.sh
#!/bin/bash
#猜数字小游戏
x=$[ RANDOM % 200 ]
while [ 1 -eq 1 ]
do
read -p "猜一个1到200之间的数" shu
if [ $x -lt $shu ];then
echo "数字猜大了"
elif [ $x -gt $shu ];then
echo "数字猜小了"
else
echo "恭喜你,猜中了嗷"
break
fi
done
[root@localhost abc]# source cai.sh
猜一个1到200之间的数100
数字猜大了
猜一个1到200之间的数50
数字猜小了
猜一个1到200之间的数75
数字猜小了
猜一个1到200之间的数88
数字猜小了
猜一个1到200之间的数94
数字猜大了
猜一个1到200之间的数92
恭喜你,猜中了嗷