当前位置: 首页 > 科技观察

“退出陷阱”使您的Bash脚本更健壮

时间:2023-03-18 11:27:27 科技观察

有一个简单实用的技巧可以使您的bash脚本更健壮——确保始终执行必要的收尾工作,即使在发生异常时也是如此。这样做的秘诀是bash提供了一个名为EXIT的伪信号,你可以捕获它,当脚本因任何原因退出时,相应的命令或函数将被执行。让我们看看它是如何工作的。基本代码结构如下所示:#!/bin/bashfunctionfinish{#你的结束代码}trapfinishEXIT你可以把你认为必须运行的任何代码放在这个结束函数中。一个很好的例子是:创建一个临时目录,然后删除它。#!/bin/bashscratch=$(mktemp-d-ttmp.XXXXXXXXXX)functionfinish{rm-rf"$scratch"}trapfinishEXIT这样,在你的核心代码中,就可以在这个$scratch目录下下载、生成和操作中间或临时数据。注1#下载所有版本的linux内核...用于科研!{1..4}专业;在{0..99}为未成年人做事;为{0..99}中的补丁级别做;dotarball="linux-${major}-${minor}-${patchlevel}.tar.bz2"curl-q"http://kernel.org/path/to/$tarball"-o"$scratch/$压缩包”||如果[-f"$scratch/$tarball"]为真;然后tarjxf"$scratch/$tarball"fidonedoneone#整合成一个文件#复制到目标位置cp"$scratch/frankenstein-linux.tar.bz2""$1"#脚本结束,scratch目录自动删除比较不使用trap怎么删除scratch目录:#!/bin/bash#Don'tdothis!scratch=$(mktemp-d-ttmp.XXXXXXXXXX)#在这里插入你的几十上百行代码#都搞定了,退出前删除目录rm-rf"$scratch"有没有问题?许多:如果发生错误并且脚本过早退出,则暂存目录及其内容不会被删除。这可能会导致数据泄露,从而导致安全问题。如果脚本设计为在脚本结束之前退出,那么您必须手动将rm命令复制并粘贴到每个退出。这也给维护带来了麻烦。如果您将来在脚本中的某处添加出口,您可能会忘记添加删除——创建一个潜在的安全漏洞。无论如何,服务都应该在线另一种场景:想象一下,你正在运行一些自动化的系统运维任务,你想暂时关闭一个服务,最后需要重启这个服务,而且一定是安全的,即使脚本运行错误。然后你可以这样做:functionfinish{#重启服务sudo/etc/init.d/somethingstart}trapfinishEXITsudo/etc/init.d/somethingstop#Maintaskcode#脚本结束,执行finish函数到重启服务一个具体的例子:比如MongoDB运行在Ubuntu服务器上,你需要写一个crond脚本来临时关闭服务,做一些日常的维护工作。你应该这样写:functionfinish{#restartservicesudoservicemongdbstart}trapfinishEXIT#closemongodservicesudoservicemongdbstop#(如果mongod配置了fork,比如replicaset,可能需要执行"sudokillall--wait/usr/bin/mongod")控制开销,有一种情况EXIT陷阱的价值尤为明显:如果你的脚本在运行过程中需要初始化昂贵的资源,确保在结束时释放它们.假设您正在AWS(亚马逊网络服务)上工作,并且您想要在脚本中创建一个图像。(术语解释:运行在亚马逊云上的服务器称为“实例”。实例是从AmazonMachineImage创建的AmazonMachineImage,通常称为“AMI”或“镜像”。AMI相当于一个特定的点在时间服务器快照。)我们可以通过基于基线AMI运行实例(例如,启动服务器)来创建自定义AMI。手动或在实例中运行脚本以进行一些更改。使用修改后的实例创建图像。如果不再需要此实例,则可以将其删除。最后一步相当重要。如果您的脚本没有删除实例,它将继续运行和计费。(等到月底帐单让你大吃一惊再哭也来不及了!)如果把AMI的创建封装在一个脚本中,我们可以使用trapEXIT来删除实例。我们也可以使用EC2的命令行工具:#!/bin/bash#定义baseAMI的IDami=$1#StoretheIDinstanceofthetemporaryinstance=''#作为一个IT人,让我们看看scratch的另一种用法目录scratch=$(mktemp-d-ttmp.XXXXXXXXXX)functionfinish{if[-n"$instance"];然后ec2-terminate-instances"$instance"firm-rf"$scratch"}trapfinishEXIT#createinstance,将输出(包括实例ID)保存到scratch目录下的一个文件中ec2-run-instances"$ami">"$scratch/run-instance"#ExtractinstanceIDinstance=$(grep'^INSTANCE'"$scratch/run-instance"|cut-f2)这里执行脚本,实例(EC2服务器)有开始运行Note2。然后你可以做任何事情:在实例中安装软件,修改配置文件等,然后创建最终版本的镜像。脚本结束时会删除实例——即使脚本因错误提前退出也是如此。(运行业务代码前请确保实例创建成功。)本文更多应用只是粗浅的介绍。多年来,我一直在使用这个bash技巧,但仍时不时地发现一些有趣的用途。您也可以将此方法应用到您自己的场景中,以提高您的bash脚本的可靠性。EndnotesNotes1.mktemp的选项-t在Linux上是可选的,在OSX上是必需的。带上这个选项可以使您的脚本更具可移植性。注2.如果只是获取实例ID,我们不需要创建文件,只写instance=$(ec2-run-instances"$ami"|grep'^INSTANCE'|cut-f2)直接地。但是将输出写入文件可以记录更多有用的信息,方便调试,也可以让代码更具可读性。