返回顶部
首页 > 资讯 > 操作系统 >十三个写好shell脚本的技巧分享
  • 665
分享到

十三个写好shell脚本的技巧分享

shell脚本技巧如何写shell脚本写shell脚本 2022-06-04 22:06:07 665人浏览 独家记忆
摘要

前言 产品的最终用户通常不懂技术,所以不管你怎么折腾产品代码都无所谓。但脚本代码不一样,它们是开发人员写给开发人员的。 有多少次,你运行./script.sh,然后输出一些东西,但却不知道它刚刚都做了些什么。这是一种

前言

产品的最终用户通常不懂技术,所以不管你怎么折腾产品代码都无所谓。但脚本代码不一样,它们是开发人员写给开发人员的。

有多少次,你运行./script.sh,然后输出一些东西,但却不知道它刚刚都做了些什么。这是一种很糟糕的脚本用户体验。我将在这篇文章中介绍如何写出具有良好开发者体验的 shell 脚本。

产品的最终用户通常不懂技术,所以不管你怎么折腾产品代码都无所谓。但脚本代码不一样,它们是开发人员写给开发人员的。

这样会导致一些问题:

  • 混乱的脚本——我知道,我们都是工程师,读得懂代码,但即使这样,也请为我们这些对 Shell 脚本不是很熟练的人考虑一下(我们在写代码时也会为你们考虑的)。
  • 满屏的日志和错误输出——就算我们也是工程师,并不代表我们了解你所做的一切。
  • 弄得一团糟却没有做好清理工作——是的,我们可以顺着你的脚本手动撤销变更,但你真的会让那些信任你的脚本的人这么做吗?

所以,我们可以通过一些方法来为自己和别人写出更好的 shell 脚本。这里给出的所有示例都可以使用与 POSIX 标准兼容的 shell 运行(#!/bin/sh),因为它是最常用的。嫌文章太长了可以只看以下总结部分:

  • 提供--help标记
  • 检查所有命令的可用性
  • 独立于当前工作目录
  • 如何读取输入:环境变量 vs. 标记
  • 打印对系统执行的所有操作
  • 如果有必要,提供--silent选项
  • 重新开启显示
  • 用动画的方式显示进度
  • 用颜色编码输出
  • 出现错误立即退出脚本
  • 自己执行清理工作
  • 在退出时使用不同的错误码
  • 在结束时打印一个新行

有时间的话可以接着往下看具体内容:

rhfSvFhlZf供--help标记

安装在系统上的二进制文件通常带有man帮助文档,但对于脚本来说就不一定了。因此我们通常需要为脚本提供-h或--help标记来打印有关如何使用脚本的信息。如果其他工程师需要修改脚本,这也可以作为脚本的内联文档:


#!/bin/sh
if [ ${#@} -ne 0 ] && [ "${@#"--help"}" = "" ]; then
 printf -- '...help...\n';
 exit 0;
fi;

这段脚本先计算参数长度(${#@} -ne 0),只有当参数长度不为零时才会检查--help标记。下一个条件会检查参数中是否存在字符串“--help” 。第一个条件是必需的,如果参数长度为零则不需要打印帮助信息。

检查所有命令的可用性

脚本通常会调用其他脚本或二进制文件。在调用可能不存在的命令时,请先检查它们是否可用。可以使用“command -v 二进制文件名称”来执行此操作,看看它的退出代码是否为零。如果命令不可用,可以告诉用户应该如何获得这个二进制文件:


#!/bin/sh
_=$(command -v Docker);
if [ "$?" != "0" ]; then
 printf -- 'You don\'t seem to have Docker installed.\n';
 printf -- 'Get it: https://www.docker.com/commUnity-edition\n';
 printf -- 'Exiting with code 127...\n';
 exit 127;
fi;
# ...

独立于当前工作目录

从不同的目录执行脚本可能会发生错误,这样的脚本没有人会喜欢。要解决这个问题,请使用绝对路径(/path/to/something)和脚本的相对路径(如下所示)。

可以使用dirname $0引用脚本的当前路径:


#!/bin/sh
CURR_DIR="$(dirname $0);"
printf -- 'moving application to /opt/app.jar';
mv "${CURR_DIR}/application.jar" /opt/app.jar;

如何读取输入:环境变量 vs. 标记

脚本通过两种方式接受输入:环境变量和选项标记(参数)。根据经验,对于不影响脚本行为的值,可以使用环境变量,而对于可能触发脚本不同流程的值,可以使用脚本参数。

不影响脚本行为的变量可能是访问令牌和 ID 之类的东西:


#!/bin/sh
# do this
export AWS_ACCESS_TOKEN='xxxxxxxxxxxx';
./provision-everything
# and not
./provisiong-everything --token 'xxxxxxxxxxx';

影响脚本行为的变量可能是需要运行实例的数量、是异步还是同步运行、是否在后台运行等参数:


#!/bin/sh
# do this
./provision-everything --async --instance-count 400
# and not
INSTANCE_COUNT=400 ASYNC=true ./provision-everything

打印对系统执行的所有操作

脚本通常会对系统执行有状态的更改。不过,由于我们不知道用户何时会向发送SIGINT,也不知道脚本错误何时可能导致脚本意外终止,因此很有必要将正在做的事情打印在终端上,这样用户就可以在不去查看脚本的情况下回溯这些步骤:


#!/bin/sh
printf -- 'Downloading required document to ./downloaded... ';
wget -o ./downloaded Https://some.site.com/downloaded;
printf -- 'Moving ./downloaded to /opt/downloaded...';
mv ./downloaded /opt/;
printf -- 'Creating symlink to /opt/downloaded...';
ln -s /opt/downloaded /usr/bin/downloaded;

在必要时提供--silent选项

有些脚本是为了将其输出传给其他脚本。虽说脚本都应该能够单独运行,不过有时候也有必要让它们把输出结果传给另一个脚本。可以利用stty -echo来实现--silent标记:


#!/bin/sh
if [ ${#@} -ne 0 ] && [ "${@#"--silent"}" = "" ]; then
 stty -echo;
fi;
# ...
# before point of intended output:
stty +echo && printf -- 'intended output\n';
# silence it again till end of script
stty -echo;
# ...
stty +echo;
exit 0;

重新开启显示

在使用stty -echo关闭脚本显示之后,如果发生致命错误,脚本将终止,而且不会恢复终端输出,这样对用户来说是没有意义的。可以使用trap来捕捉SIGINT和其他操作系统级别的信号,然后使用stty echo打开终端显示:


#!/bin/sh
error_handle() {
 stty echo;
}
if [ ${#@} -ne 0 ] && [ "${@#"--silent"}" = "" ]; then
 stty -echo;
 trap error_handle INT;
 trap error_handle TERM;
 trap error_handle KILL;
 trap error_handle EXIT;
fi;
# ...

用动画的方式显示进度

有些命令需要运行很长时间,并非所有脚本都提供了进度条。在用户等待异步任务完成时,可以通过一些方式告诉他们脚本仍在运行。比如在while循环中打印一些信息:


#!/bin/sh
printf -- 'PerfORMing asynchronous action..';
./trigger-action;
DONE=0;
while [ $DONE -eq 0 ]; do
 ./async-checker;
 if [ "$?" = "0" ]; then DONE=1; fi;
 printf -- '.';
 sleep 1;
done;
printf -- ' DONE!\n';

或者可以做一些更好玩的小玩意儿,比如 http://mywiki.wooledge.org/BashFAQ/034。

用颜色编码输出

在脚本中调用其他二进制文件或脚本时,对它们的输出进行颜色编码,这样就可以知道哪个输出来自哪个脚本或二进制文件。这样我们就不需要在满屏的黑白输出文本中查找想要的输出结果。

理想情况下,脚本应该输出白色(默认的,前台进程),子进程应该使用灰色(通常不需要,除非出现错误),使用绿色表示成功,红色表示失败,黄色表示警告。


#!/bin/sh
printf -- 'doing something... \n';
printf -- '\033[37m someone else's output \033[0m\n';
printf -- '\033[32m SUCCESS: yay \033[0m\n';
printf -- '\033[33m WARNING: hmm \033[0m\n';
printf -- '\033[31m ERROR: fubar \033[0m\n';

可以使用\033[Xm,其中X代表颜色代码。有些脚本使用\e而不是\033,但要注意\e不适用于所有的 UNIX 系统。

正确示范

可在.sh 中使用的所有颜色和修饰符 https://misc.floGISoft.com/bash/tip_colors_and_formatting。

出现错误立即退出脚本

set -e表示从当前位置开始,如果出现任何错误都将触发EXIT。相反,set +e表示不管出现任何错误继续执行脚本。

如果脚本是有状态的(每个后续步骤都依赖前一个步骤),那么请使用set -e,在脚本出现错误时立即退出脚本。如果要求所有命令都要执行完(很少会这样),那么就使用set +e。


#!/bin/sh
set +e;
./script-1;
./script-2; #rhfSvFhlZf does not depend on ./script-1
./script-3; # does not depend on ./script-2
set -e;
./script-4;
./script-5; # depends on success of ./script-4
# ...

自己执行清理工作

大多数脚本在出现错误时不会执行清理工作,能够做好这方面工作的脚本实属罕见,但这样做其实很有用,还可以省下不少时间。前面已经给出过示例,让stty恢复正常,并借助trap命令来执行清理工作:


#!/bin/sh
handle_exit_code() {
 ERROR_CODE="$?";
 printf -- "an error occurred. cleaning up now... ";
 # ... cleanup code ...
 printf -- "DONE.\nExiting with error code ${ERROR_CODE}.\n";
 exit ${ERROR_CODE};
}
trap "handle_exit_code" EXIT;
# ... actual script...

在退出时使用不同的错误码

在绝大多数 shell 脚本中,exit 0 表示执行成功,exit 1 表示发生错误。对错误与错误码进行一对一的映射,这样有助于脚本调试。


#!/bin/sh
# ...
if [ "$?" != "0" ]; then
 printf -- 'X happened. Exiting with status code 1.\n';
 exit 1;
fi;
# ...
if [ "$?" != "0" ]; then
 printf -- 'Y happened. Exiting with status code 2.\n';
 exit 2;
fi;

这样做有另一个额外的好处,就是其他脚本在调用你的脚本时,可以根据错误码来判断发生了什么错误。

在结束时打印一个新行

如果你有在遵循脚本的最佳实践,那么可能会使用printf代替echo(它在不同系统中的行为有所差别)。问题是printf在命令结束后不会自动添加一个新行,导致控制台看起来是这样的:

看起来是多么的平淡

这样一点也不酷,可以通过简单的方式打印一个新行:


#!/bin/sh
# ... your awesome script ...
printf -- '\n';
exit 0;

这样就可以得到:

好多了哈

别人会感谢你这么做的。

总结  

这篇文章大致总结了一些简单易用的技巧,让 shell 脚本更易于调试和使用。

原文链接:https://codeburst.io/13-tips-tricks-for-writing-shell-scripts-with-awesome-ux-19a525ae05ae

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

--结束END--

本文标题: 十三个写好shell脚本的技巧分享

本文链接: https://lsjlt.com/news/19631.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 十三个写好shell脚本的技巧分享
    前言 产品的最终用户通常不懂技术,所以不管你怎么折腾产品代码都无所谓。但脚本代码不一样,它们是开发人员写给开发人员的。 有多少次,你运行./script.sh,然后输出一些东西,但却不知道它刚刚都做了些什么。这是一种...
    99+
    2022-06-04
    shell脚本技巧 如何写shell脚本 写shell脚本
  • 分享Python 的十个小技巧
      一. 列表、字典、集合、元组的使用  from random import randint, sample  # 列表解析  data = [randint(-10, 10) for _ in xrange(10)]  filter(l...
    99+
    2023-01-31
    小技巧 Python
  • 25个好用的Shell脚本常用命令分享
    1.列出所有目录使用量,并按大小排序。 ls|xargs du -h|sort -rn #不递归下级目录使用du -sh 2.查看文件排除以#开关和空白行,适合查看配置文件。 egrep -v "^#|^$...
    99+
    2022-06-04
    好用 脚本 常用命令
  • 8个实用的Shell脚本分享
    几个Shell脚本的例子,觉得还不错。 【例子:001】判断输入为数字,字符或其他 #!/bin/bash read -p "Enter a number or string here:" inpu...
    99+
    2022-06-04
    脚本 Shell
  • 48个Shell脚本使用小技巧
    这篇文章主要讲解了“48个Shell脚本使用小技巧”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“48个Shell脚本使用小技巧”吧!0. shell 调试代码如下:sh -x somefil...
    99+
    2023-06-09
  • 分享9个好用的Python技巧
    目录1.引言2.Trick 13.Trick 24.Trick35.Trick46.Trick57.Trick68.Trick79.Trick810.Trick911.总结1.引言 ...
    99+
    2024-04-02
  • Shell脚本编写技巧分享:Go语言+日志记录+LeetCode算法练习
    Shell脚本编写技巧分享:Go语言 日志记录 LeetCode算法练习 在Shell脚本编写中,我们常常需要记录日志、调用其他语言进行计算等。本文将介绍如何使用Go语言编写Shell脚本中的日志记录和LeetCode算法练习,帮助你更好地...
    99+
    2023-06-20
    shell 日志 leetcode
  • 写出健壮Bash Shell脚本技巧教程
    本篇内容介绍了“写出健壮Bash Shell脚本技巧教程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用set -u你因为没有对变量初始化...
    99+
    2023-06-09
  • 分享5个JavaScript的写法小技巧
    目录前言过滤空值数组对象解构分隔数字箭头函数直接返回对象await 链条总结前言 JavaScript 易上手,但是难以全面掌握;它有许多“怪癖”,只有在长时...
    99+
    2024-04-02
  • 分享shell编程中的几个小技巧
    1、打印一些头信息command << dilimiter…………dilimiter 以分界符号dilimiter中的内容作为命令的标准输入常用在echo命令中,这样就避免了没输出一行就要使...
    99+
    2022-06-04
    几个 小技巧 shell
  • 向大家分享一个shell脚本的坑
    打算在跳板机上写一个shell脚本,批量检查远程服务器上的main进程是否在健康运行中。先找出其中一台远程机器,查看main进程运行情况[root@two002 tmp]# ps -ef|grep m...
    99+
    2023-06-06
  • Python知识之列表的十个小技巧分享
    目录一、提要    二、十个典型功能2.1 倒排列表  reverse()2.2 更换列表排列顺序 2.3 函数的生成器参数2.4 ...
    99+
    2023-01-04
    Python知识 Python列表 Python列表技巧
  • 写出健壮Bash Shell脚本的一些技巧总结
    许多人用Shell脚本完成一些简单任务,而且变成了他们生命的一部分。不幸的是,shell脚本在运行异常时会受到非常大的影响。在写脚本时将这类问题最小化是十分必要的。本文中我将介绍一些让bash脚本变得健壮的...
    99+
    2022-06-04
    健壮 脚本 技巧
  • 分享9个实战及面试常用Linux Shell脚本编写
    注意事项 1)开头加解释器:#!/bin/bash 2)语法缩进,使用四个空格;多加注释说明。 3)命名建议规则:变量名大写、局部变量小写,函数名小写,名字体现出实际作用。 4)默认变量是全局的,在函数中变量local指...
    99+
    2022-06-04
    shell 脚本编写 linux shell 脚本
  • 十个简单使用的Python自动化脚本分享
    目录1.给照片添加水印2.检测文本文件的相似性3.对文件内容进行加 密4.将照片转换为PDF5.修改照片的长与宽6.对于照片的其他操作7.测试网速8.货币汇率的转换9.生成...
    99+
    2024-04-02
  • 分享13个好用到起飞的Python技巧
    目录前言列表1. 将两个列表合并到一个字典中2.将两个或多个列表合并为一个列表3. 对字典列表进行排序4. 对字符串列表进行排序5. 根据另一个列表对列表进行排序6. 将列表映射到字...
    99+
    2024-04-02
  • 分享Python 的24个编程超好用技巧
    目录1、ALL OR ANY2、BASHPLOTIB3、COLLECTIONS4、DIR5、EMOJI6、FROM_FUTURE_IMPORT7、GEOPY8、HOWDOI9、INS...
    99+
    2024-04-02
  • Python数据处理的三个实用技巧分享
    目录1 Pandas 移除某列2 统计标题单词数3 Genre 频次统计我使用的 Pandas 版本如下,顺便也导入 Pandas 库。 >>> import pa...
    99+
    2024-04-02
  • 实现大小写字母转换的shell脚本分享
    这篇文章主要讲解了“实现大小写字母转换的shell脚本分享”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“实现大小写字母转换的shell脚本分享”吧!代码如下:#!/bin/sh #edit ...
    99+
    2023-06-09
  • 获取shell脚本自身所在目录的Shell脚本分享
    前几天写的七牛的参赛demo,用bash写了一个便捷安装的脚本,涉及到了路径相关的判断,从stackoverflow,加上自己的实践整理一下。 简单版 下面是一个最简单的实现,可以解决大多数问题,缺陷是对于...
    99+
    2022-06-04
    脚本 目录 shell
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作