Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 手动实现mkstemp_Shell_Temporary Files - Fatal编程技术网

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
的替代品相同。我可能会将此标记为答案,但我会将其保留一段时间,以防有人发现代码有任何问题

编辑:
不幸的是,这种方法需要一个版本 Cp>代码>未被广泛支持的<代码> -n>代码>标志(不覆盖),但即使目标文件存在但空的话,也不总是有效的,因为<代码> CP <代码>将认为它已经是一个有效的副本,并退出了代码< 0 > /代码>的状态。因此,
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"
}