当前位置:  开发笔记 > 编程语言 > 正文

在意外的bash退出中删除创建的临时文件

如何解决《在意外的bash退出中删除创建的临时文件》经验,为你挑选了4个好方法。

我正在从bash脚本创建临时文件.我在处理结束时删除它们,但由于脚本运行了很长时间,如果我在运行期间将其删除或只是CTRL-C,则不会删除临时文件.
有没有办法在执行结束之前捕获这些事件并清理文件?

此外,这些临时文件的命名和位置是否有某种最佳实践?
我目前不确定使用:

TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...

TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...

或者是否有更好的解决方案?



1> Chris AtLee..:

我通常会创建一个目录来放置所有临时文件,然后立即创建一个EXIT处理程序,以便在脚本退出时清理此目录.

MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT

如果您将所有临时文件放在下面$MYTMPDIR,那么在大多数情况下,当您的脚本退出时,它们都将被删除.使用SIGKILL杀死进程(kill -9)会立即终止进程,因此在这种情况下您的EXIT处理程序将无法运行.


+1肯定在EXIT上使用陷阱,而不是愚蠢的TERM/INT/HUP /你能想到的任何其他东西.虽然,记得**引用**你的参数扩展,我也会*建议你*单*引用你的陷阱:陷阱'rm -rf"$ TMPDIR"'退出
小点:使用$()而不是单个反引号.
单引号,因为如果稍后你的脚本中你的陷阱将继续工作,你决定清理和更改TMPDIR因为环境.
@ OgrePsalm33:http://stackoverflow.com/questions/4708549/shell-programming-whats-the-difference-between-command-and-command
@AlexanderTorstling代码应该始终是单引号,以防止注入导致任意代码执行.如果您将数据扩展为bash代码STRING,那么该数据现在可以执行任何代码,这会导致无辜的错误和空白,但也会出现破坏性错误,例如因奇怪的原因清除homedir或引入安全漏洞.请注意,trap会使用一串bash代码,这些代码将在以后进行评估.所以稍后当陷阱发生时,单引号将会消失,并且只会出现语法双引号.

2> Paul Tomblin..:

您可以设置一个" 陷阱 "在退出时执行或在control-c上执行清理.

trap "{ rm -f $LOCKFILE; }" EXIT

或者,我最喜欢的一个unix-isms是打开一个文件,然后在你打开文件时删除它.该文件保留在文件系统上,您可以读取和写入该文件,但是一旦程序退出,该文件就会消失.但是不知道你怎么在bash中这样做.

BTW:我将支持mktemp而不是使用你自己的解决方案的一个论点:如果用户预期你的程序将创建巨大的临时文件,他可能想要设置TMPDIR更大的地方,比如/ var/tmp.mktemp认识到,您的手动解决方案(第二个选项)没有.TMPDIR=/var/tmp gvim -d foo bar例如,我经常使用.


使用Bash,`exec 5 <> $ TMPFILE`将文件描述符5绑定到$ TMPFILE作为读写,你可以使用`<&5`,`>&5`和`/ proc/$$/fd/5`( Linux)此后.唯一的问题是Bash缺乏"寻求"功能......
关于`trap`的几个注释:没有办法陷入`SIGKILL`(按设计,因为它立即终止执行).因此,如果可能发生这种情况,请制定一个后备计划(例如`tmpreaper`).其次,陷阱不是累积的 - 如果你要执行多个动作,它们都必须在`trap`命令中.处理多个清理操作的一种方法是定义一个函数(如果需要,可以在程序进行时重新定义它)并引用:`trap cleanup_function EXIT`.

3> Brian Campbe..:

您希望使用trap命令来处理退出脚本或CTRL-C之类的信号.有关详细信息,请参阅" 高级Bash脚本编制指南 ".

对于你的临时文件,使用basename $0是一个好主意,并提供一个模板,为足够的临时文件提供空间:

tempfile() {
    tempprefix=$(basename "$0")
    mktemp /tmp/${tempprefix}.XXXXXX
}

TMP1=$(tempfile)
TMP2=$(tempfile)

trap 'rm -f $TMP1 $TMP2' EXIT


@RuslanKabalin并非所有系统都有`tempfile`命令,而我所知道的所有合理的现代系统都有`mktemp`命令.
小点:使用$()而不是单个反引号.并将双引号放在$ 0附近,因为它可能包含空格.

4> Alex..:

请记住,选择的答案是bashism,这意味着解决方案

trap "{ rm -f $LOCKFILE }" EXIT

只能在bash中工作(如果你是dash经典的话,它不会捕获Ctrl + c sh),但是如果你想要兼容性,那么你仍然需要枚举你想要捕获的所有信号.

还要记住,当脚本退出陷阱时,始终执行信号"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 

这个解决方案将为您提供更多控制,因为您可以在最终退出(preExit函数)之前运行实际信号时运行一些代码,如果需要,您可以在实际EXIT信号上运行一些代码(退出的最后阶段)

推荐阅读
保佑欣疼你的芯疼
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有