macOS 上的 mktemp 不支持 $TMPDIR

Kus*_*nda 9 environment-variables mktemp macos

我之前已经注意到这一点,但在我回答“如何将目录移动到同名目录中? ”时它又被提出来了:

mktemp在MacOS实用程序不表现一样在Linux或BSD(或至少OpenBSD的)的同名的相对于所述公用事业TMPDIR环境变量。

当前目录下创建一个临时文件,我通常可以说

tmdfile=$(TMPDIR=. mktemp)
Run Code Online (Sandbox Code Playgroud)

或者

tmpfile=$(TMPDIR=$PWD mktemp)
Run Code Online (Sandbox Code Playgroud)

(对于带有 的临时目录也类似mktemp -d)。

在 macOS 上,我必须通过给它一个实际模板来强制该实用程序使用当前目录,如

tmpfile=(mktemp ./tmp.XXXXXXXX)
Run Code Online (Sandbox Code Playgroud)

因为使用更方便的tmpfile=$(TMPDIR=. mktemp)将忽略该TMPDIR变量并/var/folders/qg/s5jp5ffx2p1fxv0hy2l_p3hm0000gn/T在类似命名的目录下或中创建文件。

mktempmacOS 上的手册提到

如果-t prefix给出该选项,mktemp将根据前缀和_CS_DARWIN_USER_TEMP_DIR配置变量(如果可用)生成模板字符串。如果_CS_DARWIN_USER_TEMP_DIR不可用,回退位置 是TMPDIR/tmp

在我的系统上,_CS_DARWIN_USER_TEMP_DIR似乎未设置:

$ getconf _CS_DARWIN_USER_TEMP_DIR
getconf: no such configuration parameter `_CS_DARWIN_USER_TEMP_DIR'
Run Code Online (Sandbox Code Playgroud)

但是例如

tmpfile=$(TMPDIR=. mktemp -t hello)
Run Code Online (Sandbox Code Playgroud)

仍然在下创建一个文件/var/folders/.../(也在使用$PWD代替 时.)。

我注意到

$ getconf DARWIN_USER_TEMP_DIR
/var/folders/qg/s5jp5ffx2p1fxv0hy2l_p3hm0000gn/T/
Run Code Online (Sandbox Code Playgroud)

但这对我没有多大帮助,因为我不知道如何更改此值。

mktemp据说macOS实用程序来自 FreeBSD,而 FreeBSD 又来自 OpenBSD(这肯定是很久以前的事了)。

题:

这是 macOS 实现中的错误(或遗漏)mktemp吗?如何从脚本中更改DARWIN_USER_TEMP_DIR值(或_CS_DARWIN_USER_TEMP_DIR手册中提到的值)(理想情况下我想取消设置它以便$TMPDIR优先)?

Jde*_*eBP 14

/var/folders/qg/s5jp5ffx2p1fxv0hy2l_p3hm0000gn/

这是您的 Darwin用户本地目录。它的名称只是您的 MacOS用户 UUID和您的 MacOS (BSD) 用户 ID串联的修改后的 base 32 编码。编码的前两个字母用作“桶”系统,以尝试将目录大小保持在较低水平。这两个字符是用户 UUID 的前 10 位编码,因为在基数 32 中,一位数字当然是 5 位。

它的子目录是您的用户本地临时目录和用户本地缓存目录。他们的名字曾经是-Caches-and-Tmp-但那些已经缩短为Cand T。很明显,所有这些名称都是固定且不可更改的,除非您愿意更改您的用户 ID 或用户 UUID。

当应用程序调用 时confstr(_CS_DARWIN_USER_TEMP_DIR,…),C 库首先尝试确保您有一个用户本地目录,然后尝试确保其中有一个用户本地临时目录。

确保您拥有用户本地目录并非易事,因为您没有对/var/folders. 因此,有一个dirhelperMach 启动守护程序,它以超级用户权限运行,并安全地创建这些目录,响应来自应用程序confstr()在其 C 库中的实现中的 Mach IPC 调用。您确实拥有对用户本地目录(一旦创建)的写访问权限,因此 C 库只是mkdir()其子库(如果它们尚不存在)。

如果成功,mktemp程序永远不会查看TMPDIR环境变量的值,因为回退 inmktemp的代码是从调用confstr()到调用,getenv()而不是相反。 confstr(_CS_DARWIN_USER_TEMP_DIR,…)几乎总是会成功。它的失败模式是诸如dirhelper无法运行启动守护程序,或者尝试创建T子目录失败并出现目录已存在以外的错误。

您可以将目录以外的内容作为T,但这将被dirhelper启动守护程序定期清理,这也是删除/var/folders. 禁用dirhelper启动守护程序会导致其自身的问题,其中最重要的是/var/folders不会被清理。拒绝自己对用户本地目录的写权限可能会干扰它的所有其他用途,它不仅仅用于T子目录。

您最好的选择(除了提供模板之外)是创建T一个符号链接,但这仍然远远不够好,因为它当然会影响您的所有正在运行的应用程序,这些应用程序可能在同一时刻想要创建一个临时文件。

无论是DARWIN_USER_TEMP_DIR也不_CS_DARWIN_USER_TEMP_DIR是变量名。它们是配置字符串的getconf实用程序和confstr()库函数的名称。