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

时间:2009-03-26 18:28:34

标签: bash exit temporary-files

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

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

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

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

或许还有更好的解决方案?

8 个答案:

答案 0 :(得分:102)

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

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

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

答案 1 :(得分:75)

你可以设置一个“trap”在退出时执行或在control-c上执行清理。

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

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

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

答案 2 :(得分:20)

您希望使用trap命令来处理退出脚本或CTRL-C之类的信号。有关详细信息,请参阅Greg's Wiki

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

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

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

trap 'rm -f $TMP1 $TMP2' EXIT

答案 3 :(得分:7)

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

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 

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

答案 4 :(得分:3)

使用带有$$的可预测文件名的替代方案是一个巨大的安全漏洞,您永远不应该考虑使用它。即使它只是您单个用户PC上的简单个人脚本。这是一个你不应该获得的非常坏的习惯。 BugTraq充满了“不安全的临时文件”事件。有关临时文件安全方面的详细信息,请参阅hereherehere

我最初想的是引用不安全的TMP1和TMP2分配,但第二个想法可能是not be a good idea

答案 5 :(得分:2)

我不敢相信这么多人认为文件名将不包含空格。如果将$ TMPDIR分配到“临时目录”,世界将崩溃。

zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps")
trap "rm -f ${zTemp@Q}" EXIT

在代码中应考虑空格和其他特殊字符(例如单引号和文件名中的回车符),这是良好的编程习惯的要求。

答案 6 :(得分:1)

我更喜欢使用tempfile以安全的方式在/ tmp中创建文件,您不必担心其命名:

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit

答案 7 :(得分:-4)

您不必费心删除使用mktemp创建的tmp文件。它们将在以后被删除。

如果可以,请使用mktemp,因为它会生成更多唯一文件,然后是'$$'前缀。它看起来像是创建临时文件的更多跨平台方式,然后显式地将它们放入/ tmp。