手动实现mkstemp

时间:2013-08-03 14:14:09

标签: shell temporary-files

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

所以,这意味着我需要自己实现一种mkstemp形式。现在最简单的方法是类似tmp="/tmp/tmp.$$.$RANDOM",虽然它起作用但并不能保证文件名不会发生冲突,所以我需要对其进行测试,但问题是在测试文件之间并且创建一个文件可能会意外地创建,因此它可能也不是一个合适的方法,至少在它自己的方法上。

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

我知道使用/tmp/tmp.$$.$RANDOM不太可能导致冲突,但是如果可以的话我想正确实现这个,因为脚本需要创建大量临时文件然后移入这个地方,我可能需要在以后的其他脚本中做同样的事情,所以做到这一点真好!

编辑: 我刚刚意识到我一直指的是mktemp到处都是mkstemp而不是{{1}}这是我真正想复制的那个(为你安全地创建一个文件)。我想我已经纠正了错误的提及,请原谅这种混乱!

2 个答案:

答案 0 :(得分:1)

通常,用于创建临时目录的命令行工具称为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

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

答案 1 :(得分: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标志(不要覆盖),但即使这样,如果目标文件存在但是为空,也不会一直有效,因为{{1将它视为已经是有效副本并退出状态为cp。因此0可能仍然是更好的选择。