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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/687014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:03:58  来源:igfitidea点击:

Removing created temp files in unexpected bash exit

bashexittemporary-files

提问by skinp

I am creating temporary files from a bash script. I am deleting them at the end of the processing, but since the script is running for quite a long time, if I kill it or simply CTRL-C during the run, the temp files are not deleted.
Is there a way I can catch those events and clean-up the files before the execution ends?

我正在从 bash 脚本创建临时文件。我在处理结束时删除它们,但由于脚本运行了很长时间,如果我在运行过程中杀死它或简单地按 CTRL-C,则不会删除临时文件。
有没有办法在执行结束之前捕获这些事件并清理文件?

Also, is there some kind of best practice for the naming and location of those temp files?
I'm currently not sure between using:

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

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

and

TMP1=/tmp/`basename 
MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT
`1.$$ TMP2=/tmp/`basename
trap "{ rm -f $LOCKFILE; }" EXIT
`2.$$ ...

Or maybe is there some better solutions?

或者也许有一些更好的解决方案?

回答by Chris AtLee

I usually create a directory in which to place all my temporary files, and then immediately after, create an EXIT handler to clean up this directory when the script exits.

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

tempfile() {
    tempprefix=$(basename "
trap "{ rm -f $LOCKFILE }" EXIT
") mktemp /tmp/${tempprefix}.XXXXXX } TMP1=$(tempfile) TMP2=$(tempfile) trap 'rm -f $TMP1 $TMP2' EXIT

If you put all your temporary files under $MYTMPDIR, then they will all be deleted when your script exits in most circumstances. Killing a process with SIGKILL (kill -9) kills the process right away though, so your EXIT handler won't run in that case.

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

回答by Paul Tomblin

You could set a "trap" to execute on exit or on a control-c to clean up.

您可以设置“陷阱”以在退出时执行或在 control-c 上进行清理。

#!/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 

Alternatively, one of my favourite unix-isms is to open a file, and then delete it while you still have it open. The file stays on the file system and you can read and write it, but as soon as your program exits, the file goes away. Not sure how you'd do that in bash, though.

或者,我最喜欢的 unix-isms 之一是打开一个文件,然后在它仍然打开时将其删除。该文件保留在文件系统上,您可以读取和写入它,但是一旦您的程序退出,该文件就会消失。不过,不确定你会如何在 bash 中做到这一点。

BTW: One argument I'll give in favour of mktemp instead of using your own solution: if the user anticipates your program is going to create huge temporary files, he might want set TMPDIRto somewhere bigger, like /var/tmp. mktemp recognizes that, your hand-rolled solution (second option) doesn't. I frequently use TMPDIR=/var/tmp gvim -d foo bar, for instance.

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

回答by Brian Campbell

You want to use the trapcommand to handle exiting the script or signals like CTRL-C. See the Greg's Wikifor details.

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

For your tempfiles, using basename $0is a good idea, as well as providing a template that provides room for enough temp files:

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

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

回答by Alex

Just keep in mind that choosen answer is bashism, which means solution as

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

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

would work only in bash (it will not catch Ctrl+c if shell is dashor classic sh), but if you want compatibility then you still need to enumerate all signals that you want to trap.

只能在 bash 中工作(如果 shell isdash或 classic sh,它不会捕获 Ctrl+c ),但是如果您想要兼容性,那么您仍然需要枚举您想要捕获的所有信号。

Also keep in mind that when script exits the trap for signal "0"(aka EXIT) is always performed resulting in double execution of trapcommand.

还要记住,当脚本退出信号“0”(又名 EXIT)的陷阱时,总是会执行导致trap命令的双重执行。

That the reason not to stack all signals in one line if there is EXIT signal.

如果有 EXIT 信号,则不将所有信号堆叠在一行中的原因。

To better understand it look at following script that will work across different systems without changes:

为了更好地理解它,请查看以下脚本,该脚本无需更改即可跨不同系统运行:

##代码##

This solution will give you more control since you can run some of your code on occurrence of actual signal just before final exit (preExitfunction) and if it needed you can run some code at actual EXIT signal (final stage of exit)

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

回答by hlovdal

The alternative of using a predictable file name with $$ is a gaping security hole and you should never, ever, ever think about using it. Even if it is just a simple personal script on your single user PC. It is a very bad habit you should not obtain. BugTraqis full of "insecure temp file" incidents. See here, hereand herefor more information on the security aspect of temp files.

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

I was initially thinking of quoting the insecure TMP1 and TMP2 assignments, but on second thought that would probably not be a good idea.

我最初想引用不安全的 TMP1 和 TMP2 分配,但转念一想这可能不是一个好主意

回答by Ruslan Kabalin

I prefer using tempfilewhich creates a file in /tmp in the safe manner and you do not have to worry about its naming:

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

##代码##

回答by Paul

I cannot believe that so many people assume that a file name will not contain a space. The world will crash if $TMPDIR is ever assigned to "temporary directory".

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

##代码##

Spaces and other special characters like single quotes and carriage returns in file names should be considered in code as a requirement of decent programming habit.

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

回答by Mykola Golubyev

You don't have to bother removing those tmp files created with mktemp. They will be deleted anyway later.

您不必费心删除那些用 mktemp 创建的 tmp 文件。无论如何,它们将被删除。

Use mktemp if you can as it generates more unique files then '$$' prefix. And it looks like more cross platform way to create temp files then explicitly put them into /tmp.

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