shell脚本
确切一点说,Shell就是一个命令行解释器,它的做用就是遵循必定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户能够用Shell来启动、挂起、中止甚至是编写一些程序。 Shell自己是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言,做为命令语言,它互动式地解释和执行用户输入的命令;做为程序设计语言,它定义了各类变量和参数,并提供了许多在高阶语言中才具备的控制结构,包括循环和分支。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、建立文档并以并行的方式协调各个程序的运行。html
shell脚本的优点在于处理操做系统底层的业务 (linux系统内部的应用都是shell脚本完成)由于有大量的linux系统命令为它作支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。例如:一键软件安装、优化、监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则。java
shell脚本
打开文本编辑器(可使用vi/vim命令来建立文件),新建一个文件test.sh,扩展名为shlinux
输入一些代码,第一行通常是这样:redis
[root@zhaocheng ~]# cat test.sh #!/bin/bash echo "Hello World" [root@zhaocheng ~]# bash test.sh Hello World
"#!" 是一个约定的标记,它告诉系统这个脚本须要什么解释器来执行,即便用哪种Shell。
echo命令用于向窗口输出文本shell
查看系统中的解释器编程
[root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh
输入echo $SHELL默认系统显示/bin/bashbootstrap
[root@localhost ~]# echo $SHELL /bin/bash
输入bash -version显示shell版本vim
[root@localhost ~]# bash -version GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
脚本书写规范
建议统一存放目录,方便运维的管理查找去执行[root@localhost ~]# mkdir /shell/scripts -pv
脚本以.sh为扩展名
开头指定脚本解释器。
开头加版本版权等信息,可配置~/.vimrc文件自动添加。
脚本不要用中文注释,尽可能用英文注释。api
代码书写优秀习惯
成对的内容一次性写出来,防止遗漏,如[ ]、' '、" "等
[ ]两端要有空格,先输入[ ],退格,输入2个空格,再退格写。
流程控制语句一次书写完,再添加内容。(if 条件 ; then 内容;fi)ddd
经过缩进让代码易读。
脚本中的引号都是英文状态下的引号,其余字符也是英文状态。数组
shell脚本的执行
[root@localhost scripts]# chmod +x test.sh [root@localhost scripts]# ls test.sh [root@localhost scripts]# ./test.sh Hello World [root@localhost scripts]# source test.sh Hello World [root@localhost scripts]# bash test.sh Hello World [root@localhost scripts]# sh test.sh Hello World
**shell的变量
变量能够分为两类:环境变量(全局变量)和普通变量(局部变量)
环境变量也可称为全局变量,能够在建立他们的Shell及其派生出来的任意子进程shell中使用,环境变量又可分为自定义环境变量和Bash内置的环境变量
普通变量也可称为局部变量,只能在建立他们的Shell函数或Shell脚本中使用。普通变量通常是由开发者用户开发脚本程序时建立的。
环境变量
能够经过env,或者export获取到系统中的环境变量**
[root@localhost scripts]# env XDG_SESSION_ID=141785 HOSTNAME=zhaocheng SHELL=/bin/bash TERM=xterm HISTSIZE=3000
输出系统中的变量
[root@localhost scripts]# echo $HOME /root [root@localhost scripts]# echo $USER root [root@localhost scripts]# echo $HISTSIZE 3000 [root@localhost scripts]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/date/soft/logstash-7.5.0/bin:/root/bin
普通变量
通常在本地设置并执行的,可是在一个脚本中去执行就是无效的
[root@localhost scripts]# xiaoming=26 [root@localhost scripts]# echo $xiaoming 26 [root@localhost scripts]# cat test.sh #!/bin/bash echo $xiaoming [root@localhost scripts]# bash test.sh
这样去执行是没法获取到普通的变量的,由于这是本地的变量值,若是将它加入到系统变量中固然这就获取到了
而刚才经过export命令查看到$PATH就是系统变量的,固然这样的,咱们执行就能在咱们脚本中直接去调用这个变量
[root@localhost scripts]# cat test.sh #!/bin/bash echo $PATH [root@localhost scripts]# bash test.sh /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/date/soft/logstash-7.5.0/bin:/root/bin
如今咱们将咱们平时定义的变量加入到shell中,通常开发一些脚本的时候方便管理也都会直接将变量在咱们全局变量中去调用,提高脚本效率与清晰,变量为大写,这种也是不建议去使用的,退出时,变量就失效,建议写到脚本中
查看咱们的系统加入的变量可使用export去查看
[root@localhost scripts]# export XIAOMING=26 [root@localhost scripts]# cat test.sh #!/bin/bash echo $XIAOMING [root@localhost scripts]# bash test.sh 26
简单示例
定义变量将变量导入到系统变量中
[root@localhost scripts]# export TENGXUN=mahuateng [root@localhost scripts]# export ALI=mayun [root@localhost scripts]# export BAIDU=liyanhong [root@localhost scripts]# cat test.sh #!/bin/bash echo $TENGXUN echo $BAIDU echo $ALI
执行效果是直接调用咱们的系统变量,而不须要脚本中再去写上面的语法,不过均可以使用,根据本身的习惯
[root@localhost scripts]# bash test.sh mahuateng liyanhong mayun
另外就是这里若是没有写进系统变量也能去调用到,可使用source,这样也能获取到
[root@localhost scripts]# LIHONGLEI=lei [root@localhost scripts]# cat test.sh #!/bin/bash echo $LIHONGLEI [root@localhost scripts]# source test.sh lei
也能够将这个加入到/etc/profile中也能够执行
[root@localhost scripts]# cat test.sh #!/bin/bash echo $PING [root@localhost scripts]# tail -1 /etc/profile PING=guo
这个须要source /etc/profile一下才能获取到
[root@localhost scripts]# source /etc/profile [root@localhost scripts]# source test.sh guo
通常当linux系统启动的时候,系统将启动一个用户shell,这个shell直接就可使用shell命令或者声明变量,好比,定义声明变量,但这个在脚本中输出为空,在局部变量须要添加$才能引用
[root@localhost scripts]# name=lili [root@localhost scripts]# echo name name [root@localhost scripts]# echo $name lili
**为何要用export命令?
其实主要是咱们定义一个变量时能够在子shell中被调用,而不须要重复去定义,可是当shell执行结束就会自动退出,该环境变量没法继续使用
变量在引号的使用
通常是特殊字符的时候须要使用'',若是是引用系统变量的话,必须使用""**
[root@tengxunyun ~]# name1=pingguo [root@tengxunyun ~]# name2='li' [root@tengxunyun ~]# name3="juzi" [root@tengxunyun ~]# name4='^^^^' [root@tengxunyun ~]# name5='&&& &&& $SHELL' [root@tengxunyun ~]# name6="kkk #### $SHELL" [root@tengxunyun ~]# echo $name1 pingguo [root@tengxunyun ~]# echo $name2 li [root@tengxunyun ~]# echo $name3 juzi [root@tengxunyun ~]# echo $name4 ^^^^ [root@tengxunyun ~]# echo $name5 &&& &&& $SHELL [root@tengxunyun ~]# echo $name6 kkk #### /bin/bash
变量使用反引号赋值
若是是变量的话,必定要加$否则它觉得是普通文件,带_划线的变量须要将前面变量{}起来
[root@tengxunyun ~]# time=`date` [root@tengxunyun ~]# echo time time [root@tengxunyun ~]# echo $time Thu Feb 20 13:34:26 CST 2020 [root@tengxunyun ~]# file=`ll` [root@tengxunyun ~]# echo $file total 4 -rw-r--r-- 1 root root 26 Feb 20 12:07 test.sh [root@tengxunyun ~]# echo ${time}_day Thu Feb 20 13:34:26 CST 2020_day [root@tengxunyun ~]# echo $time-day Thu Feb 20 13:34:26 CST 2020-day
**编写脚本的时候咱们须要将注释加到脚本的开头,这样的话,能够增长咱们的脚本的规范
使用vimrc文件**
[root@zhaocheng ~]# cat .vimrc autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2, "##############################################################") call setline(3, "# File Name: ".expand("%")) call setline(4, "# Version: V1.0") call setline(5, "# Author: clsn") call setline(6, "# Organization: http://blog.znix.top") call setline(7, "# Created Time : ".strftime("%F %T")) call setline(8, "# Description:") call setline(9, "##############################################################") call setline(10, "") endif endfunc
位置变量
$0获取当前的shell脚本的文件名,$1也就是获取的第二个参数,$2是获取的第二个参数,${11}当参数超过9以上就须要使用{}引发来
[root@zhaocheng ~]# cat test.sh #!/bin/bash echo $0 echo "第一个参数:"$1 echo "第二个参数:"$2 echo "第11个参数:"${11} [root@zhaocheng ~]# bash test.sh 1 3 3 5 6 78 8 89 9 654 77 test.sh 第一个参数:1 第二个参数:3 第11个参数:77
$#至关于列出总共多少个参数
[root@zhaocheng ~]# cat test.sh #!/bin/bash echo $0 echo "第一个参数:"$1 echo "第二个参数:"$2 echo "第11个参数:"${11} echo "列出有多少个参数:"$# [root@zhaocheng ~]# bash test.sh 66 99 00 9990 test.sh 第一个参数:66 第二个参数:99 第11个参数: 列出有多少个参数:4
*$至关于列出全部的参数**
[root@zhaocheng ~]# cat test.sh #!/bin/bash echo $0 echo "第一个参数:"$1 echo "第二个参数:"$2 echo "第11个参数:"${11} echo "列出有多少个参数:"$# echo "列出全部输出的参数:"$* [root@zhaocheng ~]# bash test.sh 99 00 88 77 66 55 44 33 test.sh 第一个参数:99 第二个参数:00 第11个参数: 列出有多少个参数:8 列出全部输出的参数:99 00 88 77 66 55 44 33
*$和¥@对比**
[root@zhaocheng ~]# set -- "It's" a nice day today [root@zhaocheng ~]# echo $1 It's [root@zhaocheng ~]# echo $2 a [root@zhaocheng ~]# echo $3 nice [root@zhaocheng ~]# echo $4 day [root@zhaocheng ~]# echo $5 today [root@zhaocheng ~]# for i in $1;do echo $i;done It's [root@zhaocheng ~]# for i in $2;do echo $i;done a [root@zhaocheng ~]# for i in $*;do echo $i;done It's a nice day today [root@zhaocheng ~]# for i in $#;do echo $i;done 5 [root@zhaocheng ~]# for i in $@;do echo $i;done It's a nice day today [root@zhaocheng ~]# for i in "$@";do echo $i;done It's a nice day today
进程状态变量
shell进程特殊状态变量
**定义变量方式
一、直接赋值
二、传递参数
三、交互式设置变量,使用read命令
read在命令行的使用**
[root@zhaocheng ~]# read 999 [root@zhaocheng ~]# echo $REPLY 999 [root@zhaocheng ~]# read kele [root@zhaocheng ~]# read kele niunai [root@zhaocheng ~]# echo $kele niunai [root@zhaocheng ~]# echo $REPLY 999
在脚本中的使用
[root@zhaocheng ~]# cat echo.sh #!/bin/bash read -p "请输入:" i echo $i [root@zhaocheng ~]# bash echo.sh 请输入:chengzhi chengzhi
赋值的使用,CHA定义变量ls
,这个是咱们的shell命令就须要使用反引号引用起来,通常比较长的目录能够直接写成变量的形式,在shell脚本中直接引用,这样看起来比较简洁,这里是找出这个文件下以.yaml结尾的文件并统计大小和倒着排序
[root@zhaocheng ~]# cat fuzhi.sh #!/bin/bash CHA=`ls` DIR=/opt/k8s/ansible echo $CHA find $DIR -name "*.yaml" |xargs du -sh |sort -nr [root@zhaocheng ~]# bash fuzhi.sh canshu.sh echo.sh fuzhi.sh tianqi.sh yum.sh 8.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/kubernetes-dashboard.yaml 8.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/kube-flannel.yaml 8.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/ingress-controller.yaml 8.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/coredns.yaml 4.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/master/files/kubelet-bootstrap-rbac.yaml 4.0K /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/master/files/apiserver-to-kubelet-rbac.yaml
交互式设置变量read
经常使用参数
-p:给出提示符。默认不支持"\n"换行
-s:静默模式。输入的内容不会回显在屏幕上
-t:给出超时时间,在达到超时时间时,read退出并返回错误
-n:限制读取N个字符就自动结束读取,若是没有读满N个字符就按下回车或遇到换行符,则也会结束读取
-N:严格要求读满N个字符才自动结束读取,即便中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符
-a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始
-p:给出提示符
read的基本用法
[root@zhaocheng ~]# cat read.sh #!/bin/bash read -p "请输入你的名字:" lakey read -s -p "请输入你的性别:" girl read -s -p "请输入你有没有对象:" ggg echo echo -e "\033[35m 你的名字是:$lakey \033[0m" echo -e "\033[35m 你的性别是:$girl \033[0m" echo -e "\033[35m 不,你不可能有对象:$ggg \033[0m"
shell中expr的用法
判断输入是否为整数,非整数返回值为2
计算变量的长度
[root@zhaocheng ~]# expr 1+1
1+1
[root@zhaocheng ~]# expr 1 + 1
2
[root@zhaocheng ~]# expr 1 1
expr: syntax error
[root@zhaocheng ~]# expr 1 * 1
1
[root@zhaocheng ~]# expr 1 \ 3
3
非整数返回值为2示例
[root@zhaocheng ~]# expr -1 + 1
0
[root@zhaocheng ~]# echo $?
1
[root@zhaocheng ~]# echo a + 1
a + 1
[root@zhaocheng ~]# expr a + 1
expr: non-integer argument
[root@zhaocheng ~]# echo $?
2
$[ ]运算符
[root@zhaocheng ~]# echo $[1+2]
3
[root@zhaocheng ~]# echo $[122]
122
[root@zhaocheng ~]# echo $[1-2]
-1
[root@zhaocheng ~]# echo $[1*2]
2
[root@zhaocheng ~]# echo $[1/2]
0
shell中的文件判断
经常使用文件测试操做符
判断这个文件有没有存在,存在的话输出0也就为真,为1也就为假
[root@zhaocheng ~]# [ -f /etc/hosts ] [root@zhaocheng ~]# echo $? 0 [root@zhaocheng ~]# [ -f /etc/hosts2 ] [root@zhaocheng ~]# echo $? 1
判断文件是否存在,返回方式
可使用颜色进行输出
判断目录是否存在
在脚本中使用判断语法目录
[root@zhaocheng ~]# cat panduan.sh #!/bin/bash DIR=/opt/k8s1 COLOR="\033[33m 目录存在 \033[0m " [ -d $DIR ] && echo -e $COLOR || echo "目录不存在" [root@zhaocheng ~]# bash panduan.sh 目录不存在
字符串判断
字符串操做符
-z 判断字符串长度
-n 判读字符串长度
[root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bash ZIFU=33 [ -z $ZIFU ] && echo "输出为空" || echo "输出有内容" [root@zhaocheng ~]# bash panduanzifu.sh 输出有内容 [root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bash ZIFU= [ -z $ZIFU ] && echo "输出为空" || echo "输出有内容" [root@zhaocheng ~]# bash panduanzifu.sh 输出为空
[root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bash ZIFU= [ -n $ZIFU ] && echo "输出为空" || echo "输出有内容" [root@zhaocheng ~]# bash panduanzifu.sh
输出为空
整数判断
整数二元比较操做符
判断两数是否相等,0为真判断成立,1为假
[root@zhaocheng ~]# [ 1 -eq 0 ] [root@zhaocheng ~]# echo $? 1 [root@zhaocheng ~]# [ 1 -eq 1 ] [root@zhaocheng ~]# echo $? 0 [root@zhaocheng ~]# [ 9 -gt 6 ] && echo "正确" || echo "错误"
正确
逻辑符号
经常使用逻辑符号
逻辑操做符与整数判断配合
45不等于40 90等于90,判读是对的就成立 [root@zhaocheng ~]# [ 45 -ne 40 -a 90 -eq 90 ] && echo 对 || echo 不对 对 下面这个只要有一个不对,这个就不成立 [root@zhaocheng ~]# [ 45 -ne 40 -a 90 -eq 98 ] && echo 对 || echo 不对 不对
-o 至少有一个是成立的就返回为真
[root@zhaocheng ~]# [ 45 -ne 40 -o 90 -eq 98 ] && echo 对 || echo 不对 对
!12,特殊用法,直接打开第12条命令
if条件语句
单分支语句
[root@zhaocheng ~]# cat dan.sh #!/bin/bash DIR=/etc/hosts if [ -f $DIR ] then echo "文件存在" fi [root@zhaocheng ~]# bash dan.sh 文件存在
多分支语句
[root@zhaocheng ~]# cat duo.sh #!/bin/bash DIR=/etc/keepalived.conf if [ -f $DIR ] then echo "存在" else echo "不存在" fi [root@zhaocheng ~]# bash duo.sh 存在
[root@zhaocheng ~]# cat bijiao.sh #!/bin/bash A=19 B=8 if [ $A -gt $B ] then echo "$A > $B" else echo "$A < $B" fi [root@zhaocheng ~]# bash bijiao.sh 19 > 8 [root@zhaocheng ~]# cat bijiao.sh #!/bin/bash A=19 B=89 if [ $A -gt $B ] then echo "$A > $B" else echo "$A < $B" fi [root@zhaocheng ~]# bash bijiao.sh 19 < 89