Shell脚本的模块化和脚本复用
日常工作中编写shell脚本是再平常不过的了,那编写过这么多的shell,当我们遇见曾经写过的相关的处理函数时,如何来复用?直接拷贝相应的代码还是“引用过来”,或者是在编写一个功能相对复杂的shell时,如何做到模块化,如何组织复杂的函数调用?
如何导入复用和模块化,就是这里要一起学习的。
我们会按照以下几个部分来学习:
1、shell执行方式不同的效果不同
2、导入模块
1、shell执行方式不同的效果不同
第一种:sh test.sh
这种方式会在我们当前进程中,再新建一个子进行去执行这个test.sh 脚本。我们能获取到的东西,也就是这个test.sh执行完的结果或者输出。
root@docker-host-03:~#more test.sh #!/bin/bash s="thisis a test file" root@docker-host-03:~#sh test.sh root@docker-host-03:~#echo $s root@docker-host-03:~#sh test.sh root@docker-host-03:~#echo $? 0 |
第二种:sourcetest.sh 或者. Test.sh
这种方式相当于是将test.sh的内容拷贝到当前进程中来执行。这样我们能获取到的内容就不仅仅是这个test.sh执行完成的结果。我们还能获取到在这个脚本中定义的全局变量,定义的功能函数。因为我们是将脚本的内容拷贝到当前文件中。
那这种方式就和我们很多编程语言中的模块导入类似。我们来验证下是不是。
root@docker-host-03:~#. test.sh root@docker-host-03:~#echo $s this is atest file root@docker-host-03:~#s=0 root@docker-host-03:~#echo $s 0 root@docker-host-03:~#source test.sh root@docker-host-03:~#echo $s this is a test file #我们可以看到这里,可以获取到变量s的内容。 |
2、导入模块
2.1)先导入一个最简单的
基于上面第一点我们提到的两种shell的执行方式中的第二种。我们利用这种“拷贝”的特性就能够实现将以前写过的功能,进行导入
比如我们写了很简单格式化输出log的函数:
root@docker-host-03:~# cat test1.sh #!/bin/bash MODULENAME=$(basename $0) LOGFILE=/tmp/logfile-`date +%Y%m%d` log_info() { #[2017-03-31 12:00:00 ] - TextName - The log message Localdatetime=`date "+%Y-%m-%d %H:%M:%S"` if[ "$1" ];then echo "[ ${datetime} ] - ${MODULENAME} - $1 " | tee -a${LOGFILE} else return 1 fi } |
上面这个log_info 函数会格式化刷出我们的日志内容。我们可以在多处复用。
我们这里的Main.sh脚本和test1.sh在同一个目录里面。我们main.sh先导入test1.sh的内容,然后使用test1.sh中已有的变量,功能函数。我们来看下main.sh的内容。
root@docker-host-03:~# cat main.sh #!/bin/bash #我们在这里通过. Test1.sh 或是source test1.sh的方式将test1.sh导入进来。 . test1.sh main() { #我们在这里就可以直接使用log_info函数了。 log_info 'This is the main shell' } main root@docker-host-03:~# ./main.sh [ 2017-03-31 15:11:23 ] - main.sh - This isthe main shell root@docker-host-03:~# more/tmp/logfile-20170331 [ 2017-03-31 15:11:39 ] - main.sh - This isthe main shell |
2.2)如果我们需要从其他地方导入其他函数
上面我们的main和test1是在同一个目录中,所以我们在main 中使用的是相对路径。如果我们需要导入的“模块”test1.sh 是放在其他的目录?或者说我们的模块存在层级关系?我们有应该如何来引入呢?
1)因我们在引入的时候,系统默认会在环境变量$PATH中去寻找我们要导入的文件。一种做法是我们将我们需要用到的公共模块放到$PATH包含的路径中。或者我们添加一个公用的路径到$PATH环境变量中,然后将我们需要用到的公有模块放到公用文件夹下。
如:
root@docker-host-03:~/test_shell# cat main.sh #!/bin/bash . test1.sh . Config.sh main() { log_info 'This is the main shell' readConf echo${conf} } main root@docker-host-03:~/test_shell# echo$PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games #在这里我们可以看到我们将两个模块放在了PATH的路径下面。 root@docker-host-03:~/test_shell# ls/usr/local/bin/test1.sh /usr/local/bin/test1.sh root@docker-host-03:~/test_shell# ls -l/usr/local/bin/Config.sh -rw-r--r-- 1 root root 59 Mar 31 15:41/usr/local/bin/Config.sh |
这里我直接将文件拷贝到了$PATH有包含的目录中。
2) 我们将模块所在的绝对路径export到PATH中:
如:
root@docker-host-03:~/test_shell/module#pwd /root/test_shell/module root@docker-host-03:~/test_shell/module#tree . ├── Config.sh └── test1.sh 0 directories, 2 files root@docker-host-03:~/test_shell/module# cd../ root@docker-host-03:~/test_shell# moremain.sh #!/bin/bash #这里我们给了一个绝对路径 MODUPATH=/root/test_shell/module export PATH=$PATH:${MODUPATH} . test1.sh . Config.sh main() { log_info 'This is the main shell' readConf echo${conf} } Main |
3) 动态的加载模块
当然如果我们在编写一个功能相对复杂的shell的时候,我们将会将这个一个整个复杂的带有结构关系的shell打包,拷贝到任何一个地方去执行。这样我们就没有办法事先知道我们的绝对路径是怎样的。比如这样的目录结构:
root@docker-host-03:~/test_shell#pwd /root/test_shell root@docker-host-03:~/test_shell#tree . ├── main.sh ├── module │ ├── Config.sh │ └── test1.sh └── module2 └── mail.sh 2directories, 4 files root@docker-host-03:~/test_shell#more main.sh #!/bin/bash #这里动态的获取到我们的绝对路径,并把模块的路径拼凑出来。 MODUPATH=$(dirname$(readlink -f $0))/module echo${MODUPATH} exportPATH=$PATH:${MODUPATH} .test1.sh .Config.sh main() { log_info 'This is the main shell' readConf echo ${conf} } Main |
4)如何避免重复多次的导入某个模块
我们要说source,其实就是将内容拷贝到同一个地方执行,那我们可以在模块中加入一个判断条件。如果发现我们模块中的某个变量已经存在,我们就return出去,不再导入后续的内容。
比如这样:
root@docker-host-03:~/test_shell#more module/test1.sh #!/bin/bash #这里我注释掉的内容就是。而且这个变量名称,尽量按照某种规则确保是唯一的变量名称。 #if [${m_log} ];then # return 0 #fi #m_log="m_log" #这一行输出是为了测试是否多次导入了。 echo"TEST IS" MODULENAME=$(basename$0) LOGFILE=/tmp/logfile-`date+%Y%m%d` log_info() { #[ 2017-03-31 12:00:00 ] - TextName - The logmessage datetime=`date "+%Y-%m-%d%H:%M:%S"` if [ "$1" ];then echo "[ ${datetime} ] - ${MODULENAME}- $1 " | tee -a ${LOGFILE} else return 1 fi } |
这里我们在注释掉的情况下,看看多次导入是什么反应。
root@docker-host-03:~/test_shell# more main.sh #!/bin/bash MODUPATH=$(dirname $(readlink -f$0))/module echo ${MODUPATH} export PATH=$PATH:${MODUPATH} . test1.sh . Config.sh main() { log_info 'This is the main shell' readConf echo${conf} } main root@docker-host-03:~/test_shell# moremodule/Config.sh #!/bin/bash . test1.sh readConf() { conf="Read the config file" } root@docker-host-03:~/test_shell# ./main.sh /root/test_shell/module TEST IS TEST IS [ 2017-03-31 16:51:09 ] - main.sh - This isthe main shell Read the config file #我们可以看到这里多次输出了TEST IS内容。 |
#将我们上面注释掉的内容去除,现在虽多次导入,但实质上只会导入一次。这样也会避免多次循环引用。
root@docker-host-03:~/test_shell# ./main.sh /root/test_shell/module TEST IS [ 2017-03-31 16:56:31 ] - main.sh - This isthe main shell Read the config file #当我们去掉了注释部分,这里就不会出现多次重复载入了。 |
-----------------------------小结-----------------
其实这里的模块复用,其实就是通过source 或则. 的方式将原本的模块内容“拷贝过来”,只是在使用的过程当中,需要注意模块路径的问题,还有层级,和多次调用的问题。
至于功能复杂的shell,我想基本也不会复杂到无法接受,基本按照一定的组织发方式就能变得清晰。并且提高复用。
大家可以自己积累一些比较常用的函数,需要用到的时候,导入,不用重复编写。比如日志,邮件告警等等。
----------------------------------------------------
转载于:https://blog.51cto.com/atong/1912179
Shell脚本的模块化和脚本复用相关推荐
- 6条shell小技巧,让脚本显得不再业余
6条shell小技巧,让脚本显得不再业余 原创作者: 58沈剑 来自公众号:架构师之路 画外音:说实话,技术思路类文章(WHY, HOW),比技术实践类(WHAT)更难写. 如何能让自己的shell显 ...
- shell脚本编程之控制脚本
技术交流QQ群:1027579432,欢迎你的加入! 1.引言 目前为止,运行脚本的唯一方式是以实时模式在命令行界面上直接运行.但是,这并不是Linux上运行脚本的唯一方式. 2.处理信号量 Linu ...
- 查看linux中的sh指向哪,什么是Linux的Shell脚本和怎么执行脚本?
1.什么是Shell?shell shell是外壳的意思,就是操做系统的外壳.咱们能够经过shell命令来操做和控制操做系统,好比Linux中的Shell命令就包括ls.cd.pwd等等.总结来讲,S ...
- shell开发跳板机功能脚本
利用Shell开发跳板机功能脚本案例 范例17_6:开发企业级Shell跳板机案例.要求用户登录到跳板机仅能执行管理员给定的选项动作,不允许以任何形式中断脚本到跳板机服务器上执行任何系统命令 方法1: ...
- shell指令可以直接在终端输入吗_简化shell终端命令输入的脚本式快捷键工具
1.解决的问题 当你需要一次输入很多个命令的时候,例如一次去多个目录删除文件 cd dir1 rm file1.temp cd ../../dir2 rm -rf dir3 当你懒得输入一个好长的命令 ...
- shell编程系列26--大型脚本工具开发实战
shell编程系列26--大型脚本工具开发实战大型脚本工具开发实战拆分脚本功能,抽象函数1.function get_all_group 返回进程组列表字符串2.function get_all_pr ...
- mongo shell连接到mongoDB及shell提示符下执行js脚本
同mysql数据库类似,mongoDB也可通过mongo客户端连接到mongod服务器来进行绝大多数日常管理.这个命令行工具就是mongo,在mysql中则是mysql.通过mongo命令可以连接到本 ...
- shell不允许输入空字符_shell脚本编程之控制脚本
点蓝色字关注"CurryCoder的程序人生" 微信公众号:CurryCoder的程序人生 欢迎关注我,一起学习,一起进步! 1.引言 目前为止,运行脚本的唯一方式是以实时模式在命 ...
- linux命令封装sh,shell脚本学习之调用脚本将文件打包zip的方法示例
前言 本文主要给大家介绍的是关于调用脚本将文件打包zip的相关资料,分享出来供大家参考学习,下面来一起看看详细的介绍: 最近刚刚接触shell脚本,写了一点简单的练手.这里是用python调用脚本执行 ...
最新文章
- 色彩(颜色)空间原理(中)
- ListView style
- IDEA构建一个mybatis项目
- TypeError: object.__init__() takes no parameters异常报错分析
- sketch里的ios控件_30个让你眼前一亮的iOS Swift UI控件!
- javaScript实现E-mail 验证
- codeforces 483B Friends and Presents 解题报告
- 思科VPP 20.05 dpdk node源码分析
- 大数据之-Hadoop3.x_MapReduce_MapTask源码解析---大数据之hadoop3.x工作笔记0126
- 利用python开发微信JS-JDK(基于python3.6)
- 商务利器 HAWK浩客G580无线演示器试用
- 澳门中区停电2小时影响396户 1人困电梯后获救
- Python开心消消乐源代码
- 高等数学--数学分析一
- php搭建聊天室,php聊天室_用PHP MySQL搭建聊天室
- 喜洋洋大战灰太狼(大结局)
- linux 常用查看日志命令--more 命令
- 传递组播与广播帧:数据待传指示传递信息(DTIM)
- 如何在MATLAB下载附加功能(下载Min-GW总结)
- SpringCloud相关jar maven管理工具不能下载(Finchley.M8)
热门文章
- Eclipse的自动build选项,制造时别忘了选上~
- 【PL/SQL】 使用游标
- 使用celery出现async的报错的解决方法
- 小程序swiper-item内容过多显示不全的解决方案
- ImportError: cannot import name ‘render_to_response‘ 解决方法
- 导致此错误的原因是什么 - “致命错误:无法找到本地咕噜声”
- 如何在熊猫数据框的列中将所有NaN值替换为零
- 使用getApplication()作为上下文的对话框抛出“无法添加窗口-令牌null不适用于应用程序”
- 数据库索引如何工作? [关闭]
- 如何显示win11隐藏文件