复习:
1,脚本文件,开头加上,#!/bin/bash,表示是用bin下面的bash来进行解释的。
2,运行bash脚本文件:
(1)bash a.sh,在新的bash里运行脚本文件。
(2)./a.sh,也是在新的bash里运行脚本文件。(前提是当前用户对这个文件有执行权限。chmod u+x a.sh,加上执行权限。)
(3). a.sh ,在当前shell里运行,就相当于把a.sh的所有代码拿到前期位置依次运。
shell脚本学习,命令是核心,变量,特殊符号,复合命令(流程控制)
在shell脚本中,经常使用同一个值,例如ip地址,可以存成一个变量,去使用,更加简洁,同时如果以后要改,也只需要改变量值,而shell脚本中的代码不需要改动,省事简单,也就意味着把这个shell脚本写活了。
x=14
echo $x 打印,$引用变量名x的值。
echo ${x} 和$x一样可以引用出变量名的值,只不过把变量名增加了边界。echo ${x}RMB,加了边界,得出1RMB,不加{},会引用$xRMB这个变量名的值,如果没有定义过这样一个变量名,就会得到空。
unset 删除一个变量
环境变量:
先bash命令,进入一个子bash,去查看刚刚上面x的变量值,echo $x,发现看不了,这时候退出子bash,回到它上级bash里,执行export x=1,这样它的子bash都可以看得见,export作用就是在当前节点,把自己的变量传给自己的所有子bash。
如果制作环境变量呢?把export x=1 放在/etc/profile/这个文件里去,放在最后一行,/etc/profile这个文件是但凡登录用户,就会立刻执行的文件。
今日内容:
一,元字符(常看看键盘)
~家目录,当前用户的家目录,是root就是根下面的root,当前用户如果是普通用户,那么他的家目录就是根下的home下的,
!取反,可以和[ ]一起使用,如查找test目录下的文件,ls /test/[!0-9].txt,就代表查看除了以0到9的单个字符的文本文件以外的文本文件。^和!一样的功能。
#,注释说明,也可以在脚本中,加上#,用来取消代码的运行。(补充,批量修改文件,首先Ctrl+v进入可视块模式,上下键选中需要修改的行,然后Shift+i进入插入模式,shift+#,然后俩下Esc键就可以添加。批量删除,首先首先Ctrl+v进入可视块模式,上下键选中需要修改的行,然后d)
$ 取变量的值,( $()可以取命令的结果的值,和``反引号一样,只不过嵌套方面,$()更好)
expr 可以做加+ 减- 乘\* 除/ 取余%,只做整数部分,不显示浮点型数字。
bc 更加强大,可以做浮点型数字,如:echo "scale=2;1/3"|bc。scale(斯给药)
& 可以让命令在后台运行,如:ping www.baidu.com & 虽然在后台运行,但是ping命令的输出结果还是要在界面上显示。输出重定向结果,无论这个结果错与对。
&& 前面一个运行成功才会运行下一个命令(第一个错误的命令也会运行,并且报错显示出来。)
; 无论前面运行是否成功,它都会运行下一条命令。
* 任意无穷个字符。(rm -rf应该上来把这个命令移动到另一个文件夹里,防止自己输入错误)。
() 命令都是在子bash中进行,(ping 1.1.1.1 &>tmp/test.log &),当前终端关了,也不影响它。
= 赋值符号,判断是否相等。name="egon", [ $name = "egon" ],运行完是没有任何输出的,需要使用$?,用来判断上一条命令是否正确,0为真,不然为失败,通常是1。
$? 测试使用。0为真。非0为假。
| 管道符号,管道就是一个共享内存
ps aux | grep ssh : ps aux把数据丢到内存里面,然后grep把这个数据从内存中取走。取走之后,共享内存就会释放掉。
ps aux | grep xxx,也得出了一个结果,echo $?得0,原因就是虽然当前系统没有xxx这个进程,但是这个过滤命令,自己产生了一个grep进程。
ps aux | grep xxx,没有结果,首字母加上{}就是去掉这个命令本身产生的进程。echo $? 得1
sdasdasd | grep yyy 没有到grep过滤,就直接失败了,echo $? 得1
发现,文件里面出现错误,还会继续执行下面的代码。这样上下代码往往是相连的,很可能下面都出错,所以要让它一旦出错就停止执行下面的代码,这样是有害的。所以在脚本文件中加入set -o errexit,意思就是遇到错误立刻退出。第一行错误的代码执行过后,就会退出。
在上面的基础上,在脚本文件中加上不存在的变量。执行的时候,执行到不存在的变量时,为空,这样也是有害的。应该先定义后引用。所以在脚本文件中加入set -o nounset,但凡脚本中执行到空的变量,就会停止程序。
sadasdasd | echo 123 ,系统不觉的它是错误的,echo $? 得0,因为echo压根不管前面是否会放入共享空间内。所以要加上set -o pipefail,只有管道错误,就会退出。
总结:
set -o errexit 遇到错误立刻退出。
set -o nounset 遇到不存在的变量,就会退出。
set -o pipefail 只要管道错误,就会退出。
用在引用变量很多,管道很多,还有可能往往在本地是可控的,如果涉及到往远程去操控的,就往往涉及到不可控因素,或者比较敏感脚本。比如远程备份,一旦失败了,本地还在打包压缩,白白浪费资源。本地部署的脚本,一般不需要加这些。
{ } 指定范围,如快速创建大量的文件,touch {1..10}{a..c}.txt ,echo ${x}取一个变量的值。
[ ] 等于test命令。
echo $x ,得111
1,test $x -eq 111 ,echo $? 0, (eq代表=号)
2,test $x -ne 111 ,echo $? 1,(ne代表不等于)
3,test $x -gt 11 ,echo $? 0,(gt代表大于号)
4,test $x -ge 111,echo $? 0,(ge 代表大于等于,没听明白)
name="egon" [ $name = "egon" ]。[ $name != "egon" ]。
把多个条件连接在一起:
[ $name = "egon" ] && [ $password = "123" ] 代表并且,
[ $name = "egon" ] || [ $password = "123" ] 代表或者。
m=111 ,n=222
首先&&连接在一起是一体的,然后才到||,如果&&执行,后面就不执行。
ping 1.1.1.1 && echo "ok" || echo "no" ping通就打印ok,
这里只是测试是否ping通,不需要一直ping,也不想看到结果。所以,-c加上次数,还有把数据引入黑洞。
ping -c 1.1.1.1 &>/dev/mull && echo "ok" || echo "no" 不会显示结果。
以上都是一条简单的判断,先一个条件,通常不想输出结果。
?任意一个字符
这里过滤出来的没有小写的a.txt,就是因为字母在这里过滤的时候,是aAbB...zZ,所以ls /test/[A-Z].txt,是从A到Z,唯独没有小a。最全的是[a-Z]。
拓展:echo $[1+3] 得4,可以进行整数计算。
二,流程控制(if判断,for循环,while循环)
1,if判断。
1,什么是if判断
依据条件的真假来决定是否做事
2,为何要有if判断
为了让计算机能够像人一样去做判断
3,如何用
if 条件;then
代码1
代码2
代码3
elif 条件2; then
代码1
代码2
else
代码1
代码2
fi
从上到下,看条件谁成立,就运行谁的子代码。如果条件都不成立,就运行else。
首先储备知识,read命令,-p就是打印,后面加上一个变量名,输入之后直接赋值
这里就是直接把用户输入的,直接赋值到后面的age变量名。
所以read age 就可以用,但是加上提示,自己也容易看的懂。
案例1
#!/bin/bash
echo "start......."
read -p "请输入您的年龄:" age
if [ $age -eq 18 ];then
echo "too young"
fi
echo "end......"
案例2
#!/bin/bash
echo "start......."
read -p "请输入您的年龄:" age
if [ $age -eq 18 ];then
echo "too young"
else
echo"too old"
fi
echo "end........"
案例3
#!/bin/bash
read -p "请输入您的分数:" score
if [ $score -ge 90 ];then
echo "优秀"
elif [ $score -ge 80 ] && [ $score -lt 90 ];then
echo "良好"
elif [ $score -ge 70 ] && [ $score -lt 80 ];then
echo "一般"
else
echo "很差"
fi
案例4
#!/bin/bash
read -p "请输入您的分数:" score 用户输入的直接赋值到后面的变量
if [ $score -ge 90 ];then 依次判断
echo "优秀"
elif [ $score -ge 80 ];then
echo "良好"
elif [ $score -ge 70 ];then
echo "一般"
else
echo "很差"
fi
案例5
#!/bin/bash 表示出是bash解释出来的。
read -p "输入用户名:" inp_user 用户输入直接赋值给后面的变量名
read -p "输入密码:" inp_pwd 用户输入直接赋值给后面的变量名
if [ $inp_user = "egon" ] && [ $inp_pwd = "123" ];then 判断
echo "登录成功" 判断成功
else 不然
echo "用户名或者密码错误"
fi
2,流程控制之while循环
1,什么是循环
2,为何要循环
3,如何用循环
#!/bin/bash
while 条件(true ,: 永远为真)
do
echo 111
done
案例1
#!/bin/bash
while true
do
read -p "请输入用户名:" inp_user
read -p "输入密码:" inp_pwd
if [ $inp_user = "egon" ] && [ $inp_pwd = "123" ];then
echo "登录成功"
else
echo "用户名或者密码错误"
fi
done
案例2
#!/bin/bash
while true
do
read -p "请输入用户名:" inp_user
read -p "输入密码:" inp_pwd
if [ $inp_user = "egon" ] && [ $inp_pwd = "123" ];then
echo "登录成功"
break
else
echo "用户名或者密码错误"
fi
done
案例3
# 多行
while 条件
do
命令1
命令2
命令3
done
# 一行
while 条件;do 命令1;命令2;命令3; done
while true;do ifconfig eth0;sleep 0.5;clear; done
三,流程控制之for循环
for循环,相对while循环,指定次数循环更强。
案例1
for i in {1..3} 就是把值逐个赋值给i。
do
echo ok1 $i
echo ok2 $i
done
案例2
for x in "aaa" 222 "ccc"
do
echo $X
done
案例3
#!/bin/bash
for i in {2..254}
do
(
ping -c1 1.1.1.$i &>/dev/null
if [ $? -eq 0 ];then
echo "1.1.1.$i ok"
else
echo "1.1.1.$i down"
fi
) &
done
这里相当于把这堆代码放到了后台,进行了200多个子bash,并发处理,时间都是一致的,不加括号,超级慢。