5个方法助你行云流水写脚本

作为一名有理想的程序员,我们或多或少都会写一些 shell 脚本,它们可能很短,只有简单的几个命令,也可能非常长,包含了系统检查、编译和运行等多个庞大复杂的任务

在安装软件的时候,你一定见过很多名为configureshell 脚本,这个脚本可以保证软件不会破坏当前系统,并且拥有可以正常安装的环境配置,实现这个脚本需要很多的逻辑和技巧。作为一名使用了多年 shell 脚本的老司机,我积累了大量关于 shell 脚本的使用技巧来提高脚本编写效率,今天,我将其中的一些精华分享出来,希望能对一些人有所帮助

初次接触脚本

刚开始的时候,我的脚本就是一系列的命令,像流水账一样,一般用来节省写多个标准 shell 语句的时间。比如发布一个 web 网站,其中一个任务就是把静态文件解压到 nginx 目录,脚本大概长这样

$ cp static_file.tar.gz /usr/nginx/home/
$ cd /usr/nginx/home/
$ tar -zxvf static_file.tar.gz

这个脚本当然节省了很多的时间,但从长远来看,这并不是一个很有用的脚本。过了一段时间,我学会了一些其他的方式来写脚本,并用来完成更有挑战性的任务,比如创建一个软件包,安装软件或者备份一个文件服务器等

1. 条件语句

就像其他的变成语言一样,条件判断是一个易用且强大的语法。条件语句可以让我们的程序按照一定的逻辑执行。我的每个脚本几乎都用到了条件语句

最基本的条件语句使用 if 标记。if 语句可以对一些条件进行判断,我们可以根据判断的结果来决定脚本的走向。例如,我们可以检查 java bin 目录是否存在,如果存在,就代表 java 已经正常安装,然后我们可以利用脚本,将 java 的运行目录放到 path 环境变量中,这样我们就可以在任意一个文件目录下运行 java 命令了

if [ -d "$JAVA_HOME/bin" ]  ; then
    PATH="$JAVA_HOME/bin;$PATH"
fi

if 条件判断还有一些高级的用法,比如我想判断一个目录是否存在,不存在则创建

[ -d "$1" ] || mkdir --parent "$1"

2. 执行权限控制

也许我们会想让脚本只能由特定的用户执行。尽管 linux 已经有了用户和组的权限控制,但还是想让脚本来控制。比如可以使用脚本来控制只能是当前 web 容器的所有者才能执行,或者只有 root 用户才能执行。linux系统给我们提供了两个环境变量去实现这个功能,其中一个是 $USER ,获取当前用户名。另一个是 $UID 获取当前用户的唯一标记

普通用户

在一个多用户,多应用的环境中,下面的示例展示了如何限制,只有 apple 这个用户才可以执行这个脚本。 if 语句可以理解为向用户提问:"执行的用户是不是 不是apple ?"。 如果发现执行人就是 apple,第一个 echo 就会被执行,后边紧跟着一个 exit 1,意味着结束脚本执行

if [ "$USER" != 'apple' ] ; then
    echo "此脚本只能由 apple 执行"
    exit 1
fi
echo "继续执行脚本"

ROOT 用户

第二个例子展示了,只有 root 用户才能执行此脚本。因为 UID0 的就是 root 用户,我们可以在判断时使用 -gt 扩展选项来禁止所有 UID 大于 0 的用户继续执行脚本

if [ "$UID" -gt 0 ] ; then
    echo "此脚本只能由 root执行"
    exit 1
fi
echo "继续执行脚本"

使用参数

和任何可以执行的文件一样,脚本文件也可以接受参数。下边会展示一些参数传递的例子。但一定要注意,要写好代码,不仅要让程序执行我们想要执行的任务,也要保证程序不要执行我们不想执行的任务。我一般在脚本中会确保在用户没有参数传递进来的时候不做任何事情。因此,我写脚本的第一件事就是使用 $# 检查脚本的参数是否传递

if [ $# -eq 0 ] ; then
    echo "参数错误"
    exit 1
fi
echo "获得了参数: $#"

多个参数

可以在命令行中传递多个参数给脚本, 脚本中对于用户提供的变量提供了很简单的获取方式,以 $ 符号开头,按照参数递增,例如 $1 $2 $3 等。 下边的例子是打印用户输入的三个参数。当然,我们还必须要注意根据参数传递的数量做不同的处理。

echo $1 $2 $3

看了上面的代码,你也许会问:是不是跳过了 $0?

嗯。。。是的,因为 $0 在脚本中也是一个非常有用的变量,他代表我们执行的脚本的名称

echo $0

对于这个参数的一个非常重要的应用就是在脚本中生成一个包含脚本名称的日志。最简单的例子大概如下

echo test >> $0.log

上边只是最简单使用,一般在使用时需要加上一些逻辑判断,比如判断文件位置是否可写等

4. 用户输入

另外一个非常有用的功能就是在脚本执行的时候让用户输入一些信息,如下

echo "请输入一个字母: "
    read word
    echo $word

这样就可以让用户在执行脚本的时候进行判断

read -p "是否安装此软件? [Y/n]: " answ
    if [ "$answ" == ’n' ] ; then
        exit 1
    fi
        echo "开始安装软件"

异常退出

几年之前,我写了一个脚本去安装最新版本的 jdk ,这个脚本的基本流程就是解压 jdk 包到指定的目录,更新 jdk 的软链,然后使用一些其他的方式让系统识别这个新版本。这就需要考虑一个问题,如果我解压 jdk 包失败了,继续执行脚本就会破坏我之前安装的 jdk 环境。所以我的脚本一定要能解决这种问题,也就是说只有解压成功才继续执行脚本,大概的源码如下

tar kxzmf jdk-8-linux-x64.tar.gz -C /home/apple/jdk --checkpoint=.500; ec=$?
if [$ec -ne 0 ] ; then
    echo "安装 jdk 失败"
    exit 1
fi

识别系统命令执行出错最简单的方法时使用 $? 变量,如下例

ls T; ec=$?; echo $ec

我们如果先执行 touch T 然后执行上边的脚本,ec 会是 0。然后删除 T 文件,调用 rm T 。再次执行脚本,ec 会变成 2,因为 T 文件没有找到,系统会抛出一个为 2 的错误标记

总结

在一些稍微复杂写的场景,我们可能就会想要用一些比较高级的语言实现,类似 Python C 或者 Java。其实很时候完全没有必要。shell 脚本非常强大,有很多值得学习和使用的东西。我希望通过上边的简单介绍能让刚刚使用 shell 并准备放弃的人了解到 一点 shell 的强大及魅力

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,338评论 0 5
  • 第 2 章 SHELL 基础知识2.1 shell脚本我们在上面简单介绍了一下什么是shell脚本,现在我们来进一...
    LiWei_9e4b阅读 1,541评论 0 0
  • 简介 shell 是类 UNIX 系统的外壳,使用 shell 用于实现人机交互的目的,我们通过它可以与内核之间进...
    noparkinghere阅读 742评论 0 1
  • 编写Shell脚本 我经常把Shell终端解释器形容是人与计算机硬件的“翻译官”,它作为用户与Linux系统内部通...
    jayafs阅读 1,235评论 0 49
  • 本文全面系统地介绍了shell脚本调试技术,包括使用echo, tee, trap等命令输出关键信息,跟踪变量的值...
    liuzg0734阅读 884评论 0 14