️This article has been over 1 years since the last update.
本文结合博主这两个月(实际使用肯定有6~7年了)的Shell系统化学习经历,介绍如何在已有Shell的基础上开始解决业务问题。
现在很多大小公司都有一个趋势,就是将开发与运维合并到一个人身上去做,即DevOps,保证最终产品运行的环境与开发环境部署一致。开发者不再是只编码业务,还要自己维护甚至开发工具。这样做的好处很明显,第一个就是发生故障后可以一个人立刻定位,不需要拉通一堆人开莫名其妙的会议;第二个就是在工具选择上不再受制于人,不怕被工具组的人吊;第三个就是使用自动化脚本,节约手工时间,提高生活质量。
如何简单入门
如果你还没有听过Shell,你需要入门一下。这里的入门指最简单的命令,比如: ls, cd, pwd 等等,此外还需要掌握正则表达式。
请直接看下面
上面的内容大概需要3~8小时初步跳读即可完成,看完了就对Shell有个概念。
如何为Shell进行调试
看完入门读物了,接下来可能需要自己尝试写脚本了。学一门语言很重要的一点就是要掌握调试,如果你不想在Shell中频繁的写echo
的话,可以使用set -x
参数,它将会把解释器的执行过程都打印出来,比如下面的+
号就是输出的调试内容。
1 | ➜ ~ set -x |
调试完成后,想关闭调试输出的话,输入set +x
即可。
How to copy and paste from StackOverflow
掌握了基本命令与调试方法后,那么如何通过Shell解决实际业务问题呢?那当然是使用搜索引擎啦,它将可靠地降低编码时间。
比如老大现在出了一个需求,要求让某台机器每天定时去取某个Windows共享目录的SQL,接着刷到数据库中。
方案一:人工搜索
分解需求
- 获取共享目录的文件
- 执行SQL刷入
- 设计定时任务
搜索需求
1. 获取共享目录的文件
首先将本句翻译为英文关键词 shell get windows shared folder,接着通过谷歌去搜索,在结果中可以发现Stackoverflow中有个大神教了一个smbclient的命令,通过阅读此答案,我就实现了此功能
1 | smbclient '//windowsserver/c$' -c 'lcd /tmp; cd $PWD; get *.sql' -U user%password |
这样,我们第一个需求就完成了
2. 执行SQL刷入
同样,将此句翻译为英文关键词,以oracle数据库为例,关键词是 oracle sql shell import sql,同样通过谷歌搜索,可以抄到一个命令
1 | sqlplus user/password@connect @/Nisarg/NEult/softpoint.sql |
但是,老大要求刷入所有的sql,这里需要有一个文件夹遍历操作,我们接着通过谷歌搜索 shell dictionary loop file, 可以发现Shell可以通过for循环或者find实现,最终脚本如下
1 | for f in *.sql |
3. 执行定时任务
这个就很简单了,你甚至可以用百度中文进行搜索,本文略,这样,你的需求就完成了。
Linux上面的命令是学不完的,不要像背六级单词那样去背下来,或者去自己造轮子,而是尽可能尝试谷歌英文搜索
shell + 功能描述
,你的需求基本上都有现成的库。
方案二:实用AI生成
考验英文concise的能力
1 | I want an example shell script that can read SQL files from a shared SMB disk and execute them in MySQL. |
Shell的高级自动化
在使用Shell过程中,一般会调用其他的工具,比如Redis、Zookeeper、SSH等,它们均自己又打开了一个终端窗口,需要手动输入非Shell的命令。对于这类需求,有两种实现方法,第一种是去找它们自带的--help
中是否有支持,第二种使用万能的Expect命令。
软件自带解析
很多软件经过迭代发展,自己搞了一套出来,一般用--help
可以搜索出来,比如Redis支持eval执行lua脚本
1 | ➜ ~ redis-cli --help |
甚至支持直接将参数放到后面
1 | ➜ ~ redis-cli SET 'key' 'val' |
很多常见的文字处理工具,比如perl, awk, sed, ex 等,都是支持自有语法的,它们明显比Shell用的更爽,跨平台、跨Shell也没有兼容性问题。
expect 自动化
Expect 可以实现互动,直接输入man expect
即可看到教程。
由于Expect命令一般不单独使用,而是通过Bash中调用expect -c
使用,因此下面的脚本默认均在Bash中运行
举个例子,清空Redis的db0缓存
1 | host="127.0.0.1" |
再举个例子,登陆SSH
1 | host=192.168.1.100 |
Shell自动化
Ansible:这个对入门文章有点超纲了,它主要是运维侧的工作,你要知道有这个东西
PaaS自动化:通过部署Kubernetes/Nomad等PaaS平台,基于Yaml进行自动化,同样超纲了。
创建自己的dotfile
dotfile是Shell中的工具类,类似于Java中的Utils.java
,你可以把下面的内容放入dotfile:
- 网上搜索到的工具类函数
- 某个业务提炼出来的函数
- 常见的alias、变量、路径
最后不妨把它放到Git中进行管理,以进行统一管理,并在调用时使用source/ln引用,这样你就不用写重复的命令,代码维护也更加简单。
1 | source /dev/stdin <<< "$(curl -s http://raw.github.com/.profile)" |
总结
个人认为,Shell是一个历史遗留问题过多的语言,其语法并不友好,Trick过多导致需要“经验”大于"流程",没有必要为了精通Shell而本末倒置。
- 能使用awk、perl,gradle等跨平台DSL的工具,尽量用跨平台工具去实现,一般来说它们的坑更少一些。
- 写Shell时切忌一上来就考虑复用,Shell是用来解决问题的,是要计算时间投入收益比的。比如某个Shell只在一台机器上跑,把路径硬编码也是无所谓的。如果以后出现复用需求后,后续再迭代改进,最后再封装下沉为自己的工具类。
- 写Shell切忌反客为主,它只是一个自动化工具,不像JAVA等饭碗工具,没有必要花费太多的时间
附录
关于单双引号
单引号'
:
除了'
中的'
,否则将所有的字符串都看作文本,不进行dereference操作。
1 | ➜ ~ echo '`whoami` is using java at "$JAVA_HOME"' |
双引号"
只对$
与 ` 进行dereference
1 | echo "`whoami` is using java at $JAVA_HOME" |