沿着/dev/null
(指向空源/接收器文件的路径),是否存在至少在 Linux 上永远不会指向有效文件的路径?这主要是为了测试我正在编写的一些脚本,我不想删除或移动不属于脚本的文件(如果它存在)。
ter*_*don 104
作为替代方案,我建议您的脚本创建一个临时目录,然后在其中查找文件名。这样,您就可以 100% 确定该文件不存在,并且您拥有完全控制权并且可以轻松地自行清理。就像是:
dir=$(mktemp -d)
if [ -e "$dir"/somefile ]; then
echo "Something is seriously wrong here, '$dir/somefile' exists!"
fi
rmdir "$dir"
Run Code Online (Sandbox Code Playgroud)
您可以用任何语言编写等效的代码,绝大多数(所有?)高级语言都有一些专用工具来处理创建和删除临时目录。与尝试猜测不应该存在的文件名相比,这似乎是一种更安全、更简洁的方法。
Kam*_*ski 86
/dev/null/foo
不能存在,除非/dev/null
是一个目录。
POSIX 要求/dev/null
是“空数据源和无限数据接收器”。我不确定是否完全不可能拥有具有这些特征的目录。尽管如此,我认为假设/dev/null
它不是 *nix 中的目录是很安全的。
请注意,如果您尝试打开,/dev/null/foo
那么您将获得ENOTDIR
(不是目录),而不是ENOENT
(没有这样的文件或目录)。对于您的测试目的,这可能会或可能不会被接受。
ilk*_*chu 33
从任何密码学手册中获取一页,如果您生成一个足够大的随机字符串,它只会以微不足道的概率存在于任何给定系统中,以至于可以忽略命中的可能性。
例如,假设你有一个工作/dev/urandom
(你应该),这样的事情会f
基于一个 128 位随机数生成一个有效的文件名:
f=/$(head -c 16 /dev/urandom |base64 |tr / ,)
Run Code Online (Sandbox Code Playgroud)
输出类似于/B90sYd,aNrcw7d7Itcb8fQ==
. (前导斜杠是固定的,故意使其成为绝对路径。尾随==
也是固定的,并且由于 Base64 填充。它们可以被忽略。)
以 1 万亿/秒的速度生成随机文件名的系统需要数万亿年才能生成由脚本生成的文件名。请注意,任何碰撞都不够,因此生日攻击不适用。这与暴力破解 128 位对称密钥基本相同。
另请参阅例如: 暴力破解 AES-128 密钥需要多长时间?
请注意,这需要一个有效的/dev/urandom
. 如果有人用包含一些已知字符串的静态文件替换它,它将不起作用,例如三个字节\x86\x89\x9e
,当 Base64 编码时,产生字符串home
;或者如果您处于例如不可用的chroot
ed 上下文中/dev/urandom
。此外,例如,没有真正的方法来初始化系统的 RNG 的嵌入式系统可能会面临问题。不要在这种情况下使用它,但在这种情况下也不要生成任何加密密钥。
作为替代方案,您可以使用空字符串。至少在 Linux 上,尝试将其用作文件名只会出现错误:
$ cat ""
cat: '': No such file or directory
$ touch ""
touch: cannot touch '': No such file or directory
Run Code Online (Sandbox Code Playgroud)
(ENOENT
顺便说一句,我发现它给出的错误 ( ) 有点有趣。有人可能认为它会说名称无效,而不是它不存在。)
请注意,如果将其放入变量中,则在扩展它时确实需要记住引号!例如f=; cat $f
,只会从标准输入读取。
$ f=
$ cat "$f"
cat: '': No such file or directory
$ touch "$f"
touch: cannot touch '': No such file or directory
Run Code Online (Sandbox Code Playgroud)
但是,如果您cd ""
在 shell 中这样做,它只会更改到当前目录。POSIX说的是“如果给定的路径]是一个空字符串,其结果是不确定的。” . 我尝试过的所有 shell 都在chdir()
调用中明确使用当前路径,例如:
/tmp$ strace -etrace=chdir zsh -c 'cd ""'
chdir("/tmp") = 0
+++ exited with 0 +++
/tmp$
Run Code Online (Sandbox Code Playgroud)
我根据之前(现已删除)的答案得到了这个想法。这可能是也可能不是系统特定的,我只在 Linux 上尝试过。买者自负。
此外,如评论中所述,如果您不关心得到的确切错误,或者使用甚至不告诉您的内容,例如[ -f ... ]
或[ -e ... ]
在 shell 中,您可以创建一个过长的文件名。
在几乎所有文件系统上,单个文件的最大长度为 255 或更少(请参阅Wikipedia上文件系统比较中的表格)。完整路径可以更长,但 256 字节的单个文件名是不可能的,并给出ENAMETOOLONG
:
$ f=$(printf %256s x | tr ' ' x)
$ touch "$f"
touch: cannot touch 'xxx...xxx': File name too long
Run Code Online (Sandbox Code Playgroud)
但是在if [ -e "$f" ]; then ...
我尝试过的所有 shell 中都可以正常工作(并且测试失败)。
(POSIX 定义说-e
“如果路径名无法解析,则为 False ”,但没有明确提及诊断。因此,也许某些实现在某些情况下可能会出错,我不确定。请告诉您是否发现了这种情况.)
(维基百科中的表格确实提到了两个具有更高每个文件长度的 Linux 文件系统,但我怀疑它们现在是否被广泛使用,而且我也知道 Linux 通常有 255 字节的限制,无论文件系统如何。)
DrS*_*don 17
由于进程 ID 永远不会为负,/proc/-1
因此永远不会存在。
即使您的 Unix 变体不支持 procfs(或未安装),这也有效!
使用文件描述符的类似方法: /dev/fd/-1
我想 Unix 的某些变体理论上可能允许 -1 的文件描述符,但这会破坏很多现有代码。
自动生成的文件系统可能还有许多其他这样的可能性。
Bri*_*ake 13
terdon已经给出了很好的答案:使用mktemp -d
. 这篇文章以更基本的方式看待这个问题,并解释了为什么这个命令通常是最好的答案。
没有永远不存在的恒定路径。但是根据您关于测试脚本的句子,如果脚本可以自行生成,则听起来变量路径也一样好。
生成这种路径的唯一方法是不断生成路径,直到生成的路径不存在。不幸的是,这可能会导致竞争条件:在您检查文件是否存在之后,其他一些程序可能会创建该文件,但在您执行取决于该文件不存在的任何操作之前。
避免这种竞争条件的最佳方法是使用其他程序应该避免的路径,例如/tmp
. 不幸的是,它/tmp
往往是全局可写的,所以现在你有一个更大的问题:其他一些用户可能会创建该文件。
您真正想要的是其他程序应该避免且其他用户无权访问的临时目录。如果目录为空则更好,因此您可以使用该目录下的任何路径。
mktemp -d
创建一个满足上一段中所有标准的目录,同时保护自己免受自己的竞争条件。完成后,您可以使用rmdir
删除目录:
dir="$(mktemp -d)"
# Use "$dir"/foo as a nonexistent path.
rmdir "$dir"
Run Code Online (Sandbox Code Playgroud)
我喜欢保持简单。我没有使用不可能存在的路径,而是使用我永远不会创建的路径,我也无法想象任何人会创建。
我需要不存在路径的测试使用类似/thisfiledoesnotexist
. 我认为这是合理的,因为:
如果您真的很偏执,那么您的测试工具可以首先测试该文件不存在,如果存在则失败。只有当文件不存在时,它才会继续进行测试。