2

好吧,在花了很长时间开发一个准备好测试的脚本之后,我现在了解到目标环境没有mkstemp(我愚蠢地相信每个 unix-y 操作系统都有),它似乎也没有任何其他常见的 temp-文件实用程序。如果有任何其他广泛可用的临时文件命令,请告诉我,但我认为我没有任何可用的。

所以,这意味着我需要实现mkstemp自己的一种形式。现在最简单的方法是这样的tmp="/tmp/tmp.$$.$RANDOM",虽然它可以工作,但不能保证文件名不会发生冲突,所以我需要对此进行测试,但问题是在测试文件和创建文件之间,该文件最终可能会意外创建,因此它也可能不是合适的方法,至少就其本身而言。

在过去,我必须实现一个与lockfile我自己等效的功能,我可以通过使用一个临时文件mv作为作弊移动到适当的位置来做到这一点(如果它返回错误,那么锁已经存在)。我倾向于认为如果文件已经存在,我可能会使用一些将失败的操作来做类似的事情,但我不确定最好的方法是什么。

我知道使用/tmp/tmp.$$.$RANDOM不太可能导致冲突,但如果可以的话,我想正确实现这一点,因为脚本需要创建大量临时文件,然后将这些文件移动到位,我可能需要这样做稍后在其他脚本中也是如此,所以正确地执行它会很好!

编辑:我刚刚意识到我一直在指代mktemp任何地方,而不是mkstemp我真正想要复制的那个(为您安全创建文件的地方)。我想我已经纠正了错误的提及,请原谅混乱!

4

2 回答 2

2

通常,用于创建临时目录的命令行工具称为mktemp,而不是mkstemp。我不确定在所有平台上使用是否安全。如果不是,您可以尝试创建一个严格的目录,umask并在该目录已经存在时失败。

mkdtemp() {
    old_mask=$(umask)
    umask 077

    name="/tmp/tmp.$$.$RANDOM"
    mkdir "$name" && echo "$name"
    retval=$?

    umask $old_mask

    return $retval
}

用法:

tempdir=$(mkdtemp) || report_failure

由于这会尝试创建目录(原子操作)而不是检查它是否存在并且在使用它生成的名称时失败,因此此操作是安全的。但是,它很容易受到拒绝服务攻击,攻击者创建许多临时目录只是为了让上述功能失败。

于 2013-08-03T16:44:43.360 回答
0

使用@larsmans 的答案,我想我可能已经找到了自己的答案。而不是使用mkdir我将cp在已知文件上使用,特别是/dev/null,它有效地创建了一个空文件,但应该以原子方式进行!

对于那些感兴趣的人,这里是代码的简化版本(请原谅任何错别字):

mkstemp() {
    umask_old=$(umask)
    umask 077

    name="/tmp/tmp.$$.$RANDOM"
    cp -n /dev/null "$name" 2> /dev/null && echo "$name"
    retval=$?

    umask "$umask_old"
    return "$retval"
}

我已经简化了上述内容以匹配 larsmans,因为我的实际解决方案将循环直到创建文件或达到尝试限制,并且我使用的行为更接近mkstemp实际选择名称的方式(使用带有尾随 X 的模板),但我认为上面显示了我在做什么,它似乎完全按照我的要求工作!

所以感谢 larsmans,您的解决方案是一个很好的替代品,mkdtemp上面的内容应该与mkstemp. 我可能会将其标记为答案,但我会暂时保留它,以防有人注意到代码有任何问题。

编辑:不幸的是,这种方法需要一个cp带有未广泛支持的-n标志的版本(不要覆盖),但如果目标文件存在但为空,即使这样也不会总是有效,因为cp它会认为它已经是一个有效的副本并退出状态为0。出于这个原因mkdir,可能仍然是更好的选择。

于 2013-08-03T18:02:50.223 回答