在意外的bash退出中删除创build的临时文件
我正在创build一个bash脚本的临时文件。 我在处理结束时将它们删除,但是由于脚本运行了相当长的时间,如果我在运行过程中杀死它或仅仅是CTRL-C,临时文件不会被删除。
有什么方法可以在执行结束之前捕捉这些事件并清理文件?
另外,这些临时文件的命名和位置是否有某种最佳实践?
我目前不确定在使用之间:
TMP1=`mktemp -p /tmp` TMP2=`mktemp -p /tmp` ...
和
TMP1=/tmp/`basename $0`1.$$ TMP2=/tmp/`basename $0`2.$$ ...
或者,也许有更好的解决scheme?
你可以设置一个“ 陷阱 ”来执行退出或在控制-c清理。
trap "{ rm -f $LOCKFILE; }" EXIT
或者,我最喜欢的unix-isms之一是打开一个文件,然后删除它,而你仍然打开它。 文件保留在文件系统上,您可以读取和写入文件,但只要程序退出,文件就会消失。 不知道你怎么这样做在bash,但。
顺便说一句:我会赞成mktemp,而不是使用自己的解决scheme的一个参数:如果用户预计您的程序将创build巨大的临时文件,他可能想要设置TMPDIR
更大的地方,如/ var / tmp。 mktemp认识到,你的手卷解决scheme(第二种select)没有。 例如,我经常使用TMPDIR=/var/tmp gvim -d foo bar
。
我通常创build一个目录,在其中放置所有的临时文件,然后立即创build一个EXIT处理程序,在脚本退出时清理此目录。
MYTMPDIR=$(mktemp -d) trap "rm -rf $MYTMPDIR" EXIT
如果你把所有的临时文件放在$MYTMPDIR
,那么当你的脚本在大多数情况下退出时,它们都将被删除。 用SIGKILL杀死一个进程(kill -9)会立即终止进程,所以你的EXIT处理程序不会在这种情况下运行。
你想使用陷阱命令来处理退出脚本或像CTRL-C的信号。 有关详细信息,请参阅高级Bash脚本指南 。
对于你的临时文件,使用basename $0
是个不错的主意,同时也提供了一个为足够临时文件提供空间的模板:
tempfile() { tempprefix=$(basename "$0") mktemp /tmp/${tempprefix}.XXXXXX } TMP1=$(tempfile) TMP2=$(tempfile) trap 'rm -f $TMP1 $TMP2' EXIT
与$$一起使用可预测的文件名的替代scheme是一个巨大的安全漏洞,你永远不应该考虑使用它。 即使它在您的单用户PC上只是一个简单的个人脚本。 这是一个非常不好的习惯,你不应该得到。 BugTraq充满了“不安全的临时文件”事件。 在 这里和这里看到有关临时文件安全方面的更多信息。
我最初是想引用不安全的TMP1和TMP2作业,但是第二个想法可能不是一个好主意 。
只要记住,select的答案是bashism
,这意味着解决scheme为
trap "{ rm -f $LOCKFILE }" EXIT
只会在bash中工作(如果shell是dash
或经典的sh
,它不会捕获Ctrl + c),但是如果你想兼容,那么你仍然需要枚举所有你想要陷阱的信号。
另请注意,当脚本退出陷阱信号“0”(又名EXIT)时,总是执行trap
命令的双重执行。
如果有EXIT信号,那么不要将所有信号叠加在一行中。
为了更好地理解它,请看下面的脚本,这些脚本可以在不改变的情况下在不同的系
#!/bin/sh on_exit() { echo 'Cleaning up...(remove tmp files, etc)' } on_preExit() { echo echo 'Exiting...' # Runs just before actual exit, # shell will execute EXIT(0) after finishing this function # that we hook also in on_exit function exit 2 } trap on_exit EXIT # EXIT = 0 trap on_preExit HUP INT QUIT TERM STOP PWR # 1 2 3 15 30 sleep 3 # some actual code... exit
这个解决scheme会给你更多的控制,因为你可以在最后退出之前运行一些你的代码( preExit
函数),如果需要你可以在实际的EXIT信号(退出的最后阶段)运行一些代码,
我更喜欢使用tempfile
,它以安全的方式在/ tmp中创build一个文件,你不必担心它的命名:
tmp=$(tempfile -s "your_sufix") trap "rm -f '$tmp'" exit
你不必去除那些用mktemp创build的tmp文件。 无论如何,他们将被删除。
如果可以,请使用mktemp,因为它会生成更多独特的文件,然后生成“$$”前缀。 它看起来像更多的跨平台的方式来创build临时文件,然后明确地把它们放入/ tmp。