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

删除意外bash退出中创建的临时文件,bash,exit,temporary-files,Bash,Exit,Temporary Files,我正在从bash脚本创建临时文件。我将在处理结束时删除它们,但由于脚本运行了相当长的时间,如果我在运行期间杀死它或简单地按CTRL-C键,则不会删除临时文件。 是否有一种方法可以捕获这些事件并在执行结束前清理文件 此外,这些临时文件的命名和位置是否有某种最佳做法? 我目前不确定是否使用: TMP1=`mktemp -p /tmp` TMP2=`mktemp -p /tmp` ... 及 或者有更好的解决方案吗?您可以设置一个“”以在退出时执行,或者设置一个control-c以进行清理 trap

我正在从bash脚本创建临时文件。我将在处理结束时删除它们,但由于脚本运行了相当长的时间,如果我在运行期间杀死它或简单地按CTRL-C键,则不会删除临时文件。
是否有一种方法可以捕获这些事件并在执行结束前清理文件

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

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

或者有更好的解决方案吗?

您可以设置一个“”以在退出时执行,或者设置一个control-c以进行清理

trap '{ rm -f -- "$LOCKFILE"; }' EXIT
或者,我最喜欢的unix ISM之一是打开一个文件,然后在您仍然打开它时将其删除。文件保留在文件系统中,您可以读取和写入它,但一旦程序退出,文件就会消失。不过,我不知道你在bash里会怎么做


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

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

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

您希望使用该命令处理退出脚本或CTRL-C等信号。有关详细信息,请参阅

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

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

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

trap 'rm -f $TMP1 $TMP2' EXIT

我通常创建一个目录,在其中放置所有临时文件,然后立即创建一个退出处理程序,在脚本退出时清理该目录

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

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

将可预测的文件名与$$一起使用是一个巨大的安全漏洞,您永远都不应该考虑使用它。即使它只是你的单用户电脑上的一个简单的个人脚本。这是一个你不应该养成的坏习惯。充满了“不安全的临时文件”事件。有关临时文件安全方面的更多信息,请参阅和


我最初考虑引用不安全的TMP1和TMP2赋值,但经过仔细考虑后,可能会这样做。

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

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

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

trap "{ rm -f $LOCKFILE }" EXIT
只能在bash中工作(如果shell是
dash
或classic
sh
,它将不会捕获Ctrl+c),但是如果您想要兼容,那么仍然需要枚举所有要捕获的信号

还要记住,当脚本退出信号“0”(也称为退出)的陷阱时,总是执行该陷阱,从而导致双重执行
trap
命令

如果存在退出信号,则不将所有信号堆叠在一行中的原因

为了更好地理解它,请查看以下脚本,这些脚本将在不作更改的情况下跨不同的系统工作:

#!/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
函数),如果需要,您可以在实际退出信号(退出的最后阶段)运行一些代码。

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


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

不要在术语上设置陷阱/INT.在退出时设置陷阱。试图根据接收到的信号来预测退出条件是愚蠢的,而且肯定不是万能的。次要的一点:使用$()而不是单个回跳。在$0左右加上双引号,因为它可能包含空格。好吧,在这个评论中,倒勾可以很好地工作,但这是一个公平的观点,使用
$()
的习惯是好的。还添加了双引号。您可以用TMP1=$(tempfile-s“XXXXXX”)@RuslanKabalin替换整个子程序。并非所有系统都有
tempfile
命令,而我所知道的所有合理的现代系统都有
mktemp
命令。+1明确地在退出时使用陷阱,不是愚蠢的术语/INT/HUP/你能想到的任何东西。不过,请记住引用您的参数扩展,我还建议您单引号引用您的陷阱:trap'rm-rf“$TMPDIR”'exitingglequotes,因为如果以后在脚本中,您决定清理并更改TMPDIR,因为发生循环,那么您的陷阱仍然有效。@AaronDigulla为什么是$()vs backticks重要吗?@OgrePsalm33:@AlexanderTorstling代码应始终为单引号,以防止注入导致任意代码执行。如果您将数据扩展到bash代码字符串中,那么该数据现在可以执行任何代码执行的操作,这些操作会导致在空白处出现无害的错误,但也会导致破坏性的错误,例如出于奇怪的原因清除homedir或引入安全漏洞。请注意,trap接受一个bash代码字符串,该字符串将在后面进行计算。所以稍后当陷阱触发时,单引号将消失,只有语法双引号。经过一段时间后由操作|文件系统本身删除?工作?还是重新启动的Solaris计算机?Pr
#!/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 
zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps")
trap "rm -f ${zTemp@Q}" EXIT