漫谈shell脚本

一. 关于shell

shell,英文是壳,外壳的意思,至于在计算机中,同样有这样的一层意思,也就是可以将shell看做是计算机系统封装的一层外壳,来供用户使用,因此,用户可以通过操纵shell也就是输入一系列命令来达到各种需要的目的,那么shell也可以被称为命令解释器

在shell下,用户可以键入一行命令而shell解释一行来使其依次执行不同的任务,这种方式称为交互式,如果在执行命令比较少的情况下交互式还是方便的,而且还使这些命令透明,用户能够分辨出因果关系;

但是如果想要执行的命令是成批的,并不需要知道过程只是想要知道结果,或者重复度很高,那么一行一行的敲入shell一行一行的解释无疑是很费时费力的,因此就可以使用另外一种处理方式就是批处理,也就是可以编写一个shell脚本,shell脚本和编程语言有些相似,同样都有变量和流程控制语句,但shell脚本是解释行的,也就是shell会将脚本中的命令一行一行的拿出来,相当于用户一行一行地键入,但是和交互式相比较起来就省事多了。



二. shell执行原理

由于历史原因,shell的种类有很多,比如bash、sh、cah、ksh、tcsh等,可以在当前路径/etc/shells下面查看系统中所有已知(但不一定安装)的shell:

对于当前的一个shell比如bash来说,当使用交互式键入一条命令的时候,它并不会自身去亲自执行一条命令,因为有可能这条命令是一条恶意的命令会侵犯当前进程,所以它会创建出一个子进程,让子进程去执行这个shell命令,但是对于shell脚本来说,当创建好一个shell脚本运行起来的时候,相当于是一条命令,这时候bash会创建一个子进程来运行shell脚本,而这个子进程同样也是一个bash,因此,当其去执行shell脚本中一条条的命令的时候,也就是相当于再会去创建出一个子进程来执行shell脚本中的一条条命令,可画图如下:

因此,在执行shell脚本中的多个命令的时候,也就需要创建出多个进程来一一执行,尽管这样,但仍然比交互式的要简便的多;



三. shell脚本

  • 运行方式

在shell脚本的编写中,‘#‘表示注释,相当于C语言中的‘//’,但是只有在第一行例外,在shell脚本中,第一行必须声明要使用的命令解释器,形式如下:

#!/bin/bash
echo "this is a shell test"

‘#‘的使用,在第一行并不表示注释,它表示该脚本使用后面的解释器/bin/bash解释执行;而‘#!‘被称为shebang;

chmod u+x shell脚本

首先,因为shell脚本并不需要经过编译,但是对于刚创建出来的shell脚本文件,一开始时并没有执行权限的,因此,可以将shell所属者的权限加上可执行,然后运行shell脚本:

命令解释器 shell脚本

要运行shell脚本,除了在脚本的编写中需要制定使用的命令解释器外,在运行起来的时候,仍然可以指定需要哪一个命令解释器来进行解释执行:

除了指定/bin/bash之外,还可以指定在当前系统中已经安装好的任何一个命令解释器;当然,除去了‘/bin/‘只使用一个bash来进行解释仍然是可行的,理所应当,其他解释器sh等也是一样:

  • shell变量

按照惯例,shell变量由全大写字母加下划线组成,有两种类型的shell变量:

环境变量:

在进程中提到,子进程会从父进程那里继承来环境变量,因此,对于执行shell脚本和脚本中的命令而创建出的子进程会继承父进程的shell环境变量;

用printenv命令可以显示当前shell进程的环境变量:


本地变量:

环境变量是所有进程都有的概念,而本地变量是shell特有的概念;本地变量只存在于当前shell进程,用set命令可以显示当前shell进程中定义的所有变量(包括环境变量和本地变量)和函数;

在shell中定义一个变量格式如下:

VALNAME=value

等号的两边是不能有空格的,因为如果用空格隔开,VALNAME就会被解释成一条命令,后面就会被解释为命令的参数;

一个变量被定以后仅存在于当前shell进程,而用export可以将其导出到环境变量中,而使用unset可以将删除:

和语言中定义变量不同的是,在shell中定义变量可以直接赋值定义而不需要指明变量的类型,比如无论是字符串、整型还是浮点型,都一律可用 VALNAME=value 来进行定义;事实上,在shell中,所有变量都是字符串,比如定义 VAL=15,VAL实际是一个字符串“15”而不是一个整数;在shell中如果对一个没有定义的变量取值,则为空字符串:

#!/bin/bash
echo "this is a shell test"

VAL1=22       //定义变量VAL1值为22
VAL2=11       //定义变量VAL2值为11
RES=0

//$(())表示将变量的值取出变成整数,只支持+-*/和()运算符,且只支持整数运算
let RES=$((VAL1+VAL2))

echo $RES     //符号 $ 表示取出变量的内容
echo ${VAL3}  //同样可以使用未定义的变量,只是内容是一个空字符串

运行结果:

上面程序示例中,取出一个变量的内容可以使用$VALNAME后面直接跟上变量名,也可以使用${VALNAME},但是加上花括号不容易引起歧义,比如:

//本意是想在VAL1的内容后面追加上abc
echo $VAL1abc   //将VAL1abc看做一个变量
echo ${VAL1}abc  //取出VAL1的值后面再跟上abc
  • 反引号 `` 和$()

大体上来说,反引号``和$()的相同之处是都可用于命令替换,就是将括起来的命令执行完毕后再交给相应的对象或者输出:

#!/bin/bash

echo `pwd`
echo $(pwd)

运行脚本:

这里要注意区分$()和$(()),前者的内容只能是命令,后者用于算术运算;

但是反引号和$()是有区别的,如下:

 VAL=10 
 echo `echo \$VAL`
 echo $(echo \$VAL)

在C语言中‘\‘是转义字符,用于除去后面的字符的特殊意义转而取其字面意思,因此,上面的代码中期望输出的是“$VAL”,但是运行程序会发现:

反引号输出的是取出了变量的内容,并没有将后面的‘$‘转义成字面值,而$()中‘\‘将‘$‘转义成字面值不再取出变量的内容,输出了“$VAL”达到了预期值;

而如果将上面的两句代码中改为:

VAL=10 
echo `echo \\$VAL`
echo $(echo \$VAL)

运行脚本:

因此分析结果:

虽然同是命令替换,但是反引号中可以看出‘\\‘相当于一个转义字符‘\‘,而$()是正常一个转义字符‘\‘转义出后面的字符表示其字面意思;

  • eval命令

eval命令用于将其后跟着的参数命令内容进行必要的替换,然后再执行命令,也就是说,eval会对命令行进行两次扫描,第一次将其重新替换,第二次才真正执行命令;

对于普通的简单的命令来说是看不到什么区别的:

 #!/bin/bash
 echo "this is a shell test"
 echo "hello world"
 eval echo "hello world"

运行脚本:

但是对于如下程序:

#!/bin/bash
echo "this is a shell test"

VAL=100
STR="echo \$VAL"
echo ${STR}
eval echo ${STR}

运行程序:

直接echo,会将变量的内容直接输出,其中STR字符串的内容中将‘$‘符号进行了转义,表示直接echo并不会取出VAL的值;

但是使用eval命令,首先会将STR的内容进行转义,之后再运行eval后面的命令行,这时候就会将VAL的值按照‘$’符号给提取出来输出,因此,eval命令的作用就可以看做是执行那些一次性并不能完成的,而是需要进行进一步的替换转置之后才能得出正确结论的命令;

  • 单中括号[ ]和双中括号[[ ]]

单中括号[]:

1. [ 用于条件测试,它并不是一个符号而是一个命令,用于判断后面条件的真假,并设置相应的退出码;和在C语言中的判断成立条件不同的是,使用[进行条件判断,如果为真则退出码为0,如果为假则退出码为1

#!/bin/bash
echo "this is a shell test"
read str 
//比较字符串时,强烈建议在左右两边都加上相同的字符,以确保当输入为空的时候仍能够进行比较
[ "X$str" == "Xred" ]
echo $?
[ "X$str" == "Xyellow" ]
echo $?
[ "X$str" == "Xblue" ]
echo $?
[ "X$str" == "Xpink" ]
echo $?

运行程序:

匹配条件成立退出码为0,不匹配则为1;

而对于整数的比较,需要使用-gt(大于)、-lt(小于)、-eq(等于)、-ge(大于等于)、-le(小于等于)来进行比较;

2. [ ]还有另外的一个用途就是作为正则表达式的一部分,描述一个字符的匹配范围;

双中括号[[ ]]:

[[ ]]同样可用于条件判断,但可以说是[ ]的加强版,因为在其内部的条件判断语句支持‘&&’、‘||’、‘>’和‘<’等C语言符号,而如果在[ ]的内部想要进行与、或的判断,就需要用到-a(与)、-o(或)来进行连接;

如下栗子:

#!/bin/bash
echo "this is a shell test"

read score//输入分数
if [ $score -ge 90 -a $score -le 100 ];then  //成绩在90到100之间为优秀
    echo "You are excellent"
elif [ $score -lt 90 ] && [ $score -ge 80 ];then //成绩在80到89之间为良好 
    echo "You are great"
elif [[ $score < 80 && $score > 59 ]];then   //成绩在60到79之间为及格
    echo "You are good"
else                                         //低于60分不及格     
    echo "Sorry,you failed"
fi

运行程序:

这里需要强调的是,[ ]和[[ ]]在shell中都是命令,因此应该将其后面跟着的参数之间加上空格分开,不然就有可能会报错,同时,在[[ ]]中仅支持‘>’和‘<’,并不支持‘>=’和‘<=’;

  • crond定时执行shell脚本

crond是Linux系统中的一个守护进程,设定启动之后可以用来定时执行指定的任务或等待处理某些任务,因此,当编辑好了一个shell脚本而想让这个shell脚本定期地去运行起来就可以将其添加用户的crontab文件中并将其启动,这样的话crond就会依照设定好的时间来运行脚本完成预定的任务;

栗子时间:

首先,在shell脚本中编写如下命令:

#!/bin/bash

DATETIME=$(date)   //提取出当前系统时间

//将特定目录下的test.txt文件拷贝到特定目录下的一个backups.txt中
$(cp /home/lounuo/test_6_12/test.txt /home/lounuo/test_6_12/backups.txt)
//将当前系统时间追加到backups.txt文件中
echo ${DATETIME} >> /home/lounuo/test_6_12/backups.txt

在当前用户下用crontab -e命令编写自身的一个crontab,路径为/var/spool/cron,文件名就为用户名:

*/1 * * * * /home/lounuo/test_6_12/test.sh

表示每隔一分钟执行一次命令也就是test.sh脚本;也就是说每隔一分钟将test.text文件的内容备份到backups.txt文件中

这里需要强调的是,在shell中仍然需要指明路径,不然crond在执行的时候就会默认在用户目录下创建出一个backups.txt文件,至于要拷贝的test.txt文件就当然找不到了,因此只会看到一个时间戳

使用不管crond是什么状态,service crond restart重启crond任务:

一开始backups.txt的内容为空;每隔一分钟修改test.txt的内容,然后再打开backups.txt,使用

tail -f backups.txt命令观察如下:

这里为了观察方便将时间设定的比较短,实际使用中可以将时间设定为更加合适的备份时间,如此一来就可以自定义一个备份的机制,每次更改一个文件中的内容都会自动备份一份,这样将shell脚本添加进crond定时任务中,就更加提高了用户与shell进行命令与结果交互的效率。

《完》

时间: 2024-08-06 14:47:30

漫谈shell脚本的相关文章

20.5 Shell脚本中的逻辑判断;20.6 文件目录属性判断;20.7 if特殊用法;20.8 20.9 cace判断(上下)

扩展: select用法 http://www.apelearn.com/bbs/thread-7950-1-1.html 20.5 Shell脚本中的逻辑判断 格式1:if 条件 ; then 语句; fi 1. 创建if1.sh测试脚本: [[email protected] ~]# vi if1.sh a=5,如果a大于3,满足这个条件,显示ok 添加内容: #!/bin/bash a=5 if [ $a -gt 3 ] then echo ok fi 2. 执行if1.sh脚本: [[e

20.1 Shell脚本介绍;20.2 Shell脚本结构和执行;20.3 date命令用法;20.4 Shell脚本中的变量

20.1 Shell脚本介绍 1. shell是一种脚本语言 aming_linux blog.lishiming.net 2. 可以使用逻辑判断.循环等语法 3. 可以自定义函数 4. shell是系统命令的集合 5. shell脚本可以实现自动化运维,能大大增加我们的运维效率 20.2 Shell脚本结构和执行 1. 开头(首行)需要加: #!/bin/bash 2. 以#开头的行作为解释说明: 3. 脚本的名字以.sh结尾,用于区分这是一个shell脚本 4. 执行.sh脚本方法有两种:

shell脚本交互:expect学习笔记及实例详解

最近项目需求,需要写一些shell脚本交互,管道不够用时,expect可以很好的实现脚本之间交互,搜索资料,发现网上好多文章都是转载的,觉得这篇文章还不错,所以简单修改之后拿过来和大家分享一下~ 1. expect是spawn: 后面加上需要执行的shell命令,比如说spawn sudo touch testfile 1.3 expect: 只有spawn执行的命令结果才会被expect捕捉到,因为spawn会启动一个进程,只有这个进程的相关信息才会被捕捉到,主要包括:标准输入的提示信息,Li

利用SHELL脚本来验证Oracle数据库RMAN备份集的有效性

利用SHELL脚本来验证Oracle数据库RMAN备份集的有效性 作者:赵全文  网名:guestart 我们生产环境的Oracle数据库都做了RMAN备份,是采用了一周的RMAN备份保留策略:除了使用RMAN备份以外,我们还使用了爱数(Eisoo)备份软件来进行备份,可以说是做到了有备无患.可是,如果有一天,Oracle数据库由于主机层面硬件原因或是数据库层面的原因不能对外提供高可用服务的时候,假设数据丢了一大部分,我们只有用RMAN备份来进行恢复,再如果发现,RMAN备份失效了,那就往地缝里

如何在linux Shell脚本里面把一个数组传递到awk内部进行处理

前段时间和几位同事讨论过一个问题:Shell脚本里面怎样把一个数组传递到awk内部进行处理? 当时没有找到方法.前两天在QQ群里讨论awk的时候,无意间又聊起这个话题.机缘巧合之下找到一个思路,特此分享. 测试环境: [root]# head -1 /etc/redhat-release Red Hat Enterprise Linux Server release 6.5 (Santiago) [root]# awk --version | head -1 GNU Awk 3.1.7 众所周知

利用shell脚本批量修改表

最近公司里因为开发新功能,程序员需要快速在某一个库里的所有表添加字段,于是就用shell脚本简单快速实现批量修改表添加字段 #!/bin/bash export mysql_bin=/usr/local/mysql/bin export database=database export tables=`$mysql_bin/mysql -Bse "use ${database};show tables;"` for i in ${tables}         do          

Shell 脚本模拟 milter 实现黑白名单及关键词过滤

程序执行流程:1. 开始接受邮件.2. 检查发件人是否在黑名单内,如果是拒绝接受;否则继续3. 检查发件人是否在白名单内,如果是接收邮件;否则继续4. 对邮件进行关键字过滤,如果邮件中包含被过滤的关键词信息,则拒绝接收   该邮件;否则,接收该邮件. Usage: sh mailfilter.sh  [-r reject-addr] [-a add-addr][-k keywords]########################################################

Linux Shell脚本攻略(1.12)

1.12 函数和参数 和其他脚本语言一样,Bash同样支持函数,并且可以传递参数. 1.12.1 函数定义和传参 #!/bin/bash function fname() #也可以用fname()代替 { echo $1,$2; #访问参数1和参数2 echo "[email protected]"; #以列表的方式一次性打印所有参数 echo "$*"; #类似于[email protected],但是参数被作为单个实体 return 0; #返回值 } fnam

shell脚本编程学习笔记(1)

在linux上编程,离不开shell,计划好好看看shell编程,并在这里做些笔记以供有相同兴趣的人分享,主要参考<shell脚本学习指南>. 学习shell脚本编程之前,需要了解脚本编程语言和编译型语言的概念. 一般很多中型.大型的程序是用编译型语言写成的,比如C.C++.Java等.这类程序从源代码编译成目标代码,直接通过计算机执行.编译型语言执行效率比较高,大多运作于底层,处理的是字节.整数.浮点数等机器层级的对象,因此实现一个具体的功能,比如"将一个目录里的所有文件复制到另外