Shell 手动实现mkstemp
好吧,在花了很长时间开发一个准备测试的脚本之后,我现在了解到目标环境没有Shell 手动实现mkstemp,shell,temporary-files,Shell,Temporary Files,好吧,在花了很长时间开发一个准备测试的脚本之后,我现在了解到目标环境没有mkstemp(我愚蠢地认为每个unix-y操作系统都有),也没有任何其他常见的临时文件实用程序。如果有任何其他广泛使用的临时文件命令,请让我知道,但我认为我没有任何可以使用的 因此,这意味着我需要自己实现一种形式的mkstemp。现在最简单的方法是像tmp=“/tmp/tmp.$$.$RANDOM”这样的方法,虽然这样做有效,但不能保证不会出现文件名冲突,因此我需要对此进行测试,但是问题是,在测试文件和创建文件之间,可能会
mkstemp
(我愚蠢地认为每个unix-y操作系统都有),也没有任何其他常见的临时文件实用程序。如果有任何其他广泛使用的临时文件命令,请让我知道,但我认为我没有任何可以使用的
因此,这意味着我需要自己实现一种形式的mkstemp
。现在最简单的方法是像tmp=“/tmp/tmp.$$.$RANDOM”
这样的方法,虽然这样做有效,但不能保证不会出现文件名冲突,因此我需要对此进行测试,但是问题是,在测试文件和创建文件之间,可能会意外地创建文件,因此,至少就其本身而言,它也可能不是一种合适的方法
在过去,我必须自己实现一个相当于lockfile
的工具,我可以通过使用mv
将临时文件移到适当位置来实现(如果它返回错误,那么锁已经存在)。我倾向于认为,如果文件已经存在,我可能会使用一些操作来做类似的事情,但我不确定最好的方法是什么
我知道使用/tmp/tmp.$$.$RANDOM
不太可能导致冲突,但如果可以的话,我希望正确地实现这一点,因为脚本需要创建大量临时文件,然后将其移动到位,我以后可能需要在其他脚本中执行同样的操作,因此正确地执行该操作非常好
编辑:
我刚刚意识到我指的是
mktemp
everywhere,而不是mkstemp
,这是我真正想要复制的(为您安全创建文件的地方)。我想我已经纠正了错误的提及,请原谅我的混淆 通常,用于创建临时目录的命令行工具称为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
由于此操作尝试创建目录(原子操作),而不是检查它是否存在,并且在使用它生成的名称时失败,因此此操作是安全的。不过,它很容易受到拒绝服务攻击,攻击者创建许多临时目录只是为了让上述功能失败。使用@larsmans的答案,我想我可能已经找到了自己的答案。我将在已知文件上使用
cp
,而不是使用mkdir
,特别是/dev/null
,它有效地创建了一个空文件,但应该以原子方式这样做
对于那些感兴趣的人,这里是代码的简化版本(请原谅任何打字错误):
我简化了上面的内容,以匹配larsmans的,因为我的实际解决方案将循环,直到创建文件或达到尝试的限制,并且我使用的行为与mkstemp
实际选择名称的方式(使用带有尾随X的模板)更为匹配,但我认为上面显示了我正在做的事情,它似乎完全符合我的要求
因此,感谢larsmans,您的解决方案是mkdtemp
的一个很好的替代品,上面的内容应该与mkstemp
的替代品相同。我可能会将此标记为答案,但我会将其保留一段时间,以防有人发现代码有任何问题
编辑:
不幸的是,这种方法需要一个版本
mkdir
可能仍然是更好的选择。如果您使用的是本地文件系统,则可以通过利用mkdir
在可移植shell脚本中实现安全的临时文件创建。请参见此处:除非我弄错了,否则mktemp
只返回一个有效的随机名称,而mkstemp
实际上也会为您创建文件,从而避免了从mktemp
中获取名称的可能性,其他人在您通过写入文件实际创建文件之前会获取该名称。您的代码对于创建临时目录很有用,但是可以为文件创建临时目录吗?创建一个唯一的目录并写入其中的文件当然是一个选项@哈拉维克:是的,但是mkstemp
不会自动生成和创建,所以它实际上与我的配方相同。与mktemp
相比,调用方的安全优势在于不再负责安全文件的创建;i、 e-我抓取一个临时文件夹,然后为方便起见在其中创建具有固定名称的文件,直到完成为止,然后丢弃整个文件夹。无论如何,这可能比通过mkstemp
抓取几个文件更好。只需touch
也会创建一个空文件。设置umask=077
实际上并不会更改文件创建掩码。感谢您发现了这个输入错误!我尝试过使用touch
,但是如果文件已经存在,它并不总是会产生错误,特别是如果它的权限限制较少,而且如果您是以root用户身份运行,在这种情况下,如果文件已经存在,touch
似乎永远不会失败,因此我认为cp
可能是更好的选择。哦,没错,touch
只更新时间戳。不要介意!嗯,我想我发现了cp
的一个问题;-n
选项(不要覆盖,我忘了在上面包括)没有得到足够广泛的支持来满足我的需要(有它的系统也有mkstemp
),这意味着如果它有松散的权限,它可能只会覆盖现有文件,
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"
}