网站模板代理,网站建设攻略,自建网站做电商,神马网站排名这八个建议#xff0c;来源于键者几年来编写 shell 脚本的一些经验和教训。事实上开始写的时候还不止这几条#xff0c;后来思索再三#xff0c;去掉几条无关痛痒的#xff0c;最后剩下八条。毫不夸张地说#xff0c;每条都是精挑细选的#xff0c;虽然有几点算是老生常谈… 这八个建议来源于键者几年来编写 shell 脚本的一些经验和教训。事实上开始写的时候还不止这几条后来思索再三去掉几条无关痛痒的最后剩下八条。毫不夸张地说每条都是精挑细选的虽然有几点算是老生常谈了。1指定bashshell 脚本的第一行#!之后应该是什么?如果拿这个问题去问别人不同的人的回答可能各不相同。我见过/usr/bin/env bash也见过/bin/bash还有/usr/bin/bash还有/bin/sh还有/usr/bin/env sh。这算是编程界的“’茴’字四种写法”了。在多数情况下以上五种写法都是等价的。但是写过程序的人都知道“少数情况”里往往隐藏着意想不到的坑。如果系统的默认 shell 不是 bash 怎么办?比如某 Linux 发行版的某个版本默认的 sh 就不是 bash。如果系统的 bash 不是在 /usr/bin/bash 怎么办?我推荐使用 /usr/bin/env bash 和 /bin/bash。前者通过env添加一个中间层让env在$PATH中搜索bash;后者则是官方背书的约定俗成的 bash 位置/usr/bin/bash不过是指向它的一个符号链接。2set -e 和 set -xOK经过一番讨论现在第一行定下来了。接下来该开始写第二行了吧?且慢!在你开始构思并写下具体的代码逻辑之前先插入一行set -e和一行set -x。set -x会在执行每一行 shell 脚本时把执行的内容输出来。它可以让你看到当前执行的情况里面涉及的变量也会被替换成实际的值。set -e会在执行出错时结束程序就像其他语言中的“抛出异常”一样。(准确说不是所有出错的时候都会结束程序见下面的注)注set -e结束程序的条件比较复杂在man bash里面足足用了一段话描述各种情景。大多数执行都会在出错时退出除非 shell 命令位于以下情况一个 pipeline 的非结尾部分比如 error | ok一个组合语句的非结尾部分比如 ok error || other一连串语句的非结尾部分比如 error; ok位于判断语句内包括 test、if、 while 等等。这两个组合在一起用可以在 debug 的时候替你节省许多时间。出于防御性编程的考虑有必要在写第一行具体的代码之前就插入它们。扪心自问写代码的时候能够一次写对的次数有多少?大多数代码在提交之前通常都经历过反复调试修改的过程。与其在焦头烂额之际才引入这两个配置不如一开始就给 debug 留下余地。在代码终于可以提交之后再考虑是否保留它们也不迟。3带上shellcheck好了现在我已经有了三行(样板)代码具体的业务逻辑一行都没写呢。是不是该开始写了?且慢!工欲善其事必先利其器。这次我就介绍一个 shell 脚本编写神器shellcheck说来惭愧虽然写了几年 shell 脚本有些语法我还是记不清楚。这时候就要依仗 shellcheck 指点一下了。shellcheck 除了可以提醒语法问题以外还能检查出 shell 脚本编写常见的 bad code。本来我的N条建议里面还有几条是关于这些 bad code 的不过考虑到 shellcheck 完全可以发掘出这些问题于是忍痛把它们都剔除在外了。毫无疑问使用 shellcheck 给我的 shell 编写技能带来了巨大的飞跃。所谓“站在巨人的肩膀上”虽然我们这些新兵蛋子技能不如老兵们强但是我们可以在装备上赶上对方啊!动动手安装一下就能结识一个循循善诱的“老师”何乐而不为?顺便一提shellcheck 居然是用 haskell 写的。谁说 haskell 只能用来装逼?4变量展开在 shell 脚本中偶尔可以看到这样的做法echo $xxx | awk/sed/grep/cut...。看起来大张形势的样子其实不过是想修改一个变量的值。杀鸡何必用牛刀?bash 内建的变量展开机制已经足以满足你各种需求!还是老方法 read the f**k manaul! man bash 然后搜索Parameter Expansion下面就是你想要的技巧。键者也写过一篇相关的文章希望能助上一臂之力玩转 Bash变量。5注意local随着代码越写越多你开始把重复的逻辑提炼成函数。有可能你会掉到 bash 的一个坑里。在 bash如果不加 local 限定词变量默认都是全局的。变量默认全局——这跟 js 和 lua 相似;但相较而言很少有 bash 教程一开始就告知你这个事实。在顶级作用域里是否是全局变量并不重要。但是在函数里面声明一个全局变量可能会污染到其他作用域(尤其在你根本没有注意到这一点的情况下)。所以对于在函数内声明的变量请务必记得加上 local 限定词。6trap 信号如果你写过稍微复杂点的在后台运行的程序应该知道 posix 标准里面“信号”是什么一回事。如果不知道直接看下一段。像其他语言一样shell 也支持处理信号。trap sighandler INT可以在接收到 SIGINT 时调用 sighandler 函数。捕获其他信号的方式以此类推。不过 trap 的主要应用场景可不是捕获哪个信号。trap 命令支持“捕获”许多不同的流程——准确来说允许用户给特定的流程注入函数调用。其中最为常用的是trap func EXIT和trap func ERR。trap func EXIT允许在脚本结束时调用函数。由于无论正常退出抑或异常退出所注册的函数都能得以调用在需要调用一个清理函数的场景下我都是用它注册清理函数而不是简单地在脚本结尾调用清理函数。trap func ERR允许在运行出错时调用函数。一个常用的技法是使用全局变量ERROR存储错误信息然后在注册的函数中根据存储的值完成对应的错误报告。把原本四分五裂的错误处理逻辑集中到一处有时候会起奇效。不过要记住程序异常退出时既会调用EXIT注册的函数也会调用ERR注册的函数。7三思后行以上几条都是具体的建议剩下两条比较务虚。这条建议的名字叫“三思而行”。其实无论写什么代码哪怕只是一个辅助脚本都要三思而行切忌粗心大意。不写脚本的时候更要记住这点。毕竟许多时候一个复杂的脚本发端于几行小小的命令。一开始写这个脚本的人也许以为它只是一次性任务。代码里难免对一些外部条件有些假定在当时也许是正常的但是随着外部环境的变化这些就成了隐藏的暗礁。雪上加霜的是几乎没有人会给脚本做测试。除非你去运行它否则不知道它是否还能正常使用。要想减缓脚本代码的腐烂速度需要在编写的时候辨清哪些是会变的依赖、哪些是脚本正常运行所不可或缺的。要有适当的抽象编写可变更的代码;同时要有防御性编程的意识给自己的代码一道护城河。8扬长避短有些时候使用 shell 写脚本就意味着难以移植、难以统一地进行错误处理、难以利索地处理数据。虽然使用外部的命令可以方便快捷地实现各种复杂的功能但作为硬币的反面不得不依靠grep、sed、awk等各种工具把它们粘合在一起。如果有兼容多平台的需求还得小心规避诸如BSD和GNU coreutilsbash版本差异之类奇奇怪怪的陷阱。由于缺乏完善的数据结构以及一致的APIshell 脚本在处理复杂的逻辑上力不从心。解决特定的问题要用合适的工具。知道什么时候用 shell什么时候切换到另外一门更通用的脚本语言(比如ruby/python/perl)这也是编写可靠 shell 脚本的诀窍。如果你的任务可以组合常见的命令来完成而且只涉及简单的数据那么 shell 脚本就是适合的锤子。如果你的任务包含较为复杂的逻辑而且数据结构复杂那么你需要用 ruby/python 之类的语言编写脚本。3月云计算在线免费训练营开讲啦5天技术免费学扫码预约抢名额▼ 如有疑问速寻达妹微信zdzc3087880280达妹QQ3535503962。精彩推荐达内教育面向全国用户提供免费课程(文中申请)都在云上你说云运维会吃香不运维的新“加码”技能—Python2019年达内学员入职中国软件百强榜完整榜单点击“