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

发布于 2024-07-15 12:41:44 字数 369 浏览 10 评论 0原文

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

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

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

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

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

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?

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 $0`1.$
TMP2=/tmp/`basename $0`2.$
...

Or maybe is there some better solutions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

过期情话 2024-07-22 12:41:44

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

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

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

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.

MYTMPDIR="$(mktemp -d)"
trap 'rm -rf -- "$MYTMPDIR"' 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.

三岁铭 2024-07-22 12:41:44

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

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

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

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

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

trap '{ rm -f -- "$LOCKFILE"; }' 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.

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 TMPDIR to 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.

不寐倦长更 2024-07-22 12:41:44

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

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

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

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

trap 'rm -f $TMP1 $TMP2' EXIT

You want to use the trap command to handle exiting the script or signals like CTRL-C. See the Greg's Wiki for details.

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

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

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

trap 'rm -f $TMP1 $TMP2' EXIT
空城缀染半城烟沙 2024-07-22 12:41:44

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

trap "{ rm -f $LOCKFILE }" EXIT

仅在 bash 中有效(如果 shell 是 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函数),如果需要,您可以在实际退出信号(退出的最后阶段)处运行一些代码

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

trap "{ rm -f $LOCKFILE }" EXIT

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

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

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

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

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

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

执笏见 2024-07-22 12:41:44

好习惯是美好的

  • 避免假设变量的值在某个超远的时间永远不会改变(特别是如果这样的错误会引发错误) .

  • Do导致陷阱立即扩展变量的值(如果适用于您的代码)。 任何用单引号传递给 trap 的变量名都会延迟其值的扩展,直到捕获之后。

  • 避免假设文件名不包含任何空格。

  • 是否使用 Bash ${VAR@Q}$(printf '%q' "$VAR")< /code> 克服由空格和其他特殊字符(例如文件名中的引号和回车符)引起的问题。


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

GOOD HABITS ARE BEAUTIFUL

  • Avoid assuming the value of a variable is never going to be changed at some super distant time (especially if such a bug would raise an error).

  • Do cause trap to expand the value of a variable immediately if applicable to your code. Any variable name passed to trap in single quotes will delay the expansion of its value until after the catch.

  • Avoid the assumption that a file name will not contain any spaces.

  • Do use Bash ${VAR@Q} or $(printf '%q' "$VAR") to overcome issues caused by spaces and other special characters like quotes and carriage returns in file names.

    zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps")
    trap "rm -f ${zTemp@Q}" EXIT
活泼老夫 2024-07-22 12:41:44

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

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

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. BugTraq is full of "insecure temp file" incidents. See here, here and here for more information on the security aspect of temp files.

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

无风消散 2024-07-22 12:41:44

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

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

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

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit
君勿笑 2024-07-22 12:41:44

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

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文