千家信息网

Linux系统shell脚本的用法

发表于:2024-11-20 作者:千家信息网编辑
千家信息网最后更新 2024年11月20日,shell脚本确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用She
千家信息网最后更新 2024年11月20日Linux系统shell脚本的用法

shell脚本
确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。 Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言,作为命令语言,它互动式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环和分支。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行的方式协调各个程序的运行。

shell脚本的优势在于处理操作系统底层的业务 (linux系统内部的应用都是shell脚本完成)因为有大量的linux系统命令为它做支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。例如:一键软件安装、优化、监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则。

shell脚本
打开文本编辑器(可以使用vi/vim命令来创建文件),新建一个文件test.sh,扩展名为sh

输入一些代码,第一行一般是这样:

[root@zhaocheng ~]# cat test.sh #!/bin/bashecho "Hello World"[root@zhaocheng ~]# bash test.sh Hello World

"#!" 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。
echo命令用于向窗口输出文本

查看系统中的解释器

[root@localhost ~]# cat /etc/shells /bin/sh/bin/bash/usr/bin/sh/usr/bin/bash/bin/tcsh/bin/csh

输入echo $SHELL默认系统显示/bin/bash

[root@localhost ~]# echo $SHELL/bin/bash

输入bash -version显示shell版本

[root@localhost ~]# bash -versionGNU 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 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文件自动添加。
脚本不要用中文注释,尽量用英文注释。

代码书写优秀习惯
成对的内容一次性写出来,防止遗漏,如[ ]、' '、" "等
[ ]两端要有空格,先输入[ ],退格,输入2个空格,再退格写。
流程控制语句一次书写完,再添加内容。(if 条件 ; then 内容;fi)ddd
通过缩进让代码易读。
脚本中的引号都是英文状态下的引号,其他字符也是英文状态。

shell脚本的执行

[root@localhost scripts]# chmod +x test.sh [root@localhost scripts]# lstest.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]# envXDG_SESSION_ID=141785HOSTNAME=zhaochengSHELL=/bin/bashTERM=xtermHISTSIZE=3000

输出系统中的变量

[root@localhost scripts]# echo $HOME/root[root@localhost scripts]# echo $USERroot[root@localhost scripts]# echo $HISTSIZE3000[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 $xiaoming26[root@localhost scripts]# cat test.sh #!/bin/bashecho $xiaoming[root@localhost scripts]# bash test.sh 

这样去执行是无法获取到普通的变量的,因为这是本地的变量值,如果将它加入到系统变量中当然这就获取到了
而刚才通过export命令查看到$PATH就是系统变量的,当然这样的,我们执行就能在我们脚本中直接去调用这个变量

[root@localhost scripts]# cat test.sh #!/bin/bashecho $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/bashecho $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/bashecho $TENGXUNecho $BAIDUecho $ALI

执行效果是直接调用我们的系统变量,而不需要脚本中再去写上面的语法,不过都可以使用,根据自己的习惯

[root@localhost scripts]# bash test.sh mahuatengliyanhongmayun

另外就是这里如果没有写进系统变量也能去调用到,可以使用source,这样也能获取到

[root@localhost scripts]# LIHONGLEI=lei[root@localhost scripts]# cat test.sh #!/bin/bashecho $LIHONGLEI[root@localhost scripts]# source test.sh lei

也可以将这个加入到/etc/profile中也可以执行

[root@localhost scripts]# cat test.sh #!/bin/bashecho $PING[root@localhost scripts]# tail -1 /etc/profilePING=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 namename[root@localhost scripts]# echo $namelili

**为什么要用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 $name1pingguo[root@tengxunyun ~]# echo $name2li[root@tengxunyun ~]# echo $name3juzi[root@tengxunyun ~]# echo $name4^^^^[root@tengxunyun ~]# echo $name5&&& &&& $SHELL[root@tengxunyun ~]# echo $name6kkk #### /bin/bash

变量使用反引号赋值
如果是变量的话,一定要加$不然它以为是普通文件,带_划线的变量需要将前面变量{}起来

[root@tengxunyun ~]# time=`date`[root@tengxunyun ~]# echo timetime[root@tengxunyun ~]# echo $timeThu Feb 20 13:34:26 CST 2020[root@tengxunyun ~]# file=`ll`[root@tengxunyun ~]# echo $filetotal 4 -rw-r--r-- 1 root root 26 Feb 20 12:07 test.sh[root@tengxunyun ~]# echo ${time}_dayThu Feb 20 13:34:26 CST 2020_day[root@tengxunyun ~]# echo $time-dayThu 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, "")    endifendfunc

位置变量

$0获取当前的shell脚本的文件名,$1也就是获取的第二个参数,$2是获取的第二个参数,${11}当参数超过9以上就需要使用{}引起来

[root@zhaocheng ~]# cat test.sh #!/bin/bashecho $0echo "第一个参数:"$1echo "第二个参数:"$2echo "第11个参数:"${11}[root@zhaocheng ~]# bash test.sh 1 3 3 5 6 78  8 89  9  654 77test.sh第一个参数:1第二个参数:3第11个参数:77

$#相当于列出总共多少个参数

[root@zhaocheng ~]# cat test.sh #!/bin/bashecho $0echo "第一个参数:"$1echo "第二个参数:"$2echo "第11个参数:"${11}echo "列出有多少个参数:"$#[root@zhaocheng ~]# bash test.sh 66 99 00 9990test.sh第一个参数:66第二个参数:99第11个参数:列出有多少个参数:4

*$相当于列出所有的参数**

[root@zhaocheng ~]# cat test.sh #!/bin/bashecho $0echo "第一个参数:"$1echo "第二个参数:"$2echo "第11个参数:"${11}echo "列出有多少个参数:"$#echo "列出所有输出的参数:"$*[root@zhaocheng ~]# bash test.sh 99 00 88 77 66 55 44 33test.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 $1It's[root@zhaocheng ~]# echo $2a[root@zhaocheng ~]# echo $3nice[root@zhaocheng ~]# echo $4day[root@zhaocheng ~]# echo $5today[root@zhaocheng ~]# for i in $1;do echo $i;doneIt's[root@zhaocheng ~]# for i in $2;do echo $i;donea[root@zhaocheng ~]# for i in $*;do echo $i;doneIt'sanicedaytoday[root@zhaocheng ~]# for i in $#;do echo $i;done5[root@zhaocheng ~]# for i in $@;do echo $i;doneIt'sanicedaytoday[root@zhaocheng ~]# for i in "$@";do echo $i;doneIt'sanicedaytoday

进程状态变量
shell进程特殊状态变量

**定义变量方式
1、直接赋值
2、传递参数
3、交互式设置变量,使用read命令

read在命令行的使用**

[root@zhaocheng ~]# read999[root@zhaocheng ~]# echo $REPLY999[root@zhaocheng ~]# read kele[root@zhaocheng ~]# read keleniunai[root@zhaocheng ~]# echo $keleniunai[root@zhaocheng ~]# echo $REPLY999

在脚本中的使用

[root@zhaocheng ~]# cat echo.sh #!/bin/bashread -p "请输入:" iecho $i[root@zhaocheng ~]# bash echo.sh 请输入:chengzhichengzhi

赋值的使用,CHA定义变量ls,这个是我们的shell命令就需要使用反引号引用起来,一般比较长的目录可以直接写成变量的形式,在shell脚本中直接引用,这样看起来比较简洁,这里是找出这个文件下以.yaml结尾的文件并统计大小和倒着排序

[root@zhaocheng ~]# cat fuzhi.sh #!/bin/bashCHA=`ls`DIR=/opt/k8s/ansibleecho $CHAfind $DIR -name "*.yaml" |xargs du -sh |sort -nr[root@zhaocheng ~]# bash fuzhi.sh canshu.sh echo.sh fuzhi.sh tianqi.sh yum.sh8.0K    /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/kubernetes-dashboard.yaml8.0K    /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/kube-flannel.yaml8.0K    /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/ingress-controller.yaml8.0K    /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/addons/files/coredns.yaml4.0K    /opt/k8s/ansible/ansible-k8s/ansible-install-k8s/roles/master/files/kubelet-bootstrap-rbac.yaml4.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/bashread -p  "请输入你的名字:" lakeyread -s -p  "请输入你的性别:" girlread -s -p  "请输入你有没有对象:" gggechoecho -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/bashDIR=/opt/k8s1COLOR="\033[33m 目录存在 \033[0m "[ -d $DIR ] && echo -e $COLOR || echo "目录不存在"[root@zhaocheng ~]# bash panduan.sh 目录不存在

字符串判断
字符串操作符

-z 判断字符串长度
-n 判读字符串长度

[root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bashZIFU=33 [ -z $ZIFU ] && echo "输出为空" || echo "输出有内容"[root@zhaocheng ~]# bash panduanzifu.sh 输出有内容[root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bashZIFU=[ -z $ZIFU ] && echo "输出为空" || echo "输出有内容"[root@zhaocheng ~]# bash panduanzifu.sh 输出为空
[root@zhaocheng ~]# cat panduanzifu.sh #!/bin/bashZIFU=[ -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/bashDIR=/etc/hostsif [ -f $DIR ]then  echo "文件存在"fi[root@zhaocheng ~]# bash dan.sh 文件存在

多分支语句

[root@zhaocheng ~]# cat duo.sh #!/bin/bashDIR=/etc/keepalived.confif [ -f $DIR ]then  echo "存在"else  echo "不存在"fi[root@zhaocheng ~]# bash duo.sh 存在
[root@zhaocheng ~]# cat bijiao.sh #!/bin/bashA=19B=8if [ $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/bashA=19B=89if [ $A -gt $B ]then  echo "$A > $B"else  echo "$A < $B"fi[root@zhaocheng ~]# bash bijiao.sh 19 < 89
0