沿着(空源/接收器文件的路径)的思路/dev/null
,是否有一条路径至少在 Linux 上永远不会指向有效文件?这主要是为了测试我正在编写的一些脚本,我不想只删除或移动不属于该脚本的文件(如果存在)。
答案1
作为替代方案,我建议您的脚本创建一个临时目录,然后在其中查找文件名。这样,您就可以 100% 确定该文件不存在,并且您可以完全控制并可以轻松地自行清理。就像是:
dir=$(mktemp -d)
if [ -e "$dir"/somefile ]; then
echo "Something is seriously wrong here, '$dir/somefile' exists!"
fi
rmdir "$dir"
您可以用任何语言编写等效的代码,绝大多数(所有?)高级语言都会有一些专用工具来处理临时目录的创建和删除。与尝试猜测不应该存在的文件名相比,这似乎是一种更安全、更干净的方法。
答案2
/dev/null/foo
不能存在,除非/dev/null
是目录。
POSIX 要求/dev/null
成为“一个空的数据源和无限的数据接收器”。我不确定是否完全不可能有一个具有这些特征的目录。尽管如此,我认为可以很安全地假设/dev/null
不是您的 *nix 中的目录。
请注意,如果您尝试打开,/dev/null/foo
那么您将得到ENOTDIR
(不是目录),而不是ENOENT
(没有这样的文件或目录)。对于您的测试目的来说,这可能可接受也可能不可接受。
答案3
借鉴任何密码学手册,如果生成足够大的随机字符串,它只会以微不足道的概率存在于任何给定系统上,以至于可以忽略命中的可能性。
例如,假设您有一个工作文件/dev/urandom
(并且您应该这样做),类似这样的内容将f
基于 128 位随机数生成有效的文件名:
f=/$(head -c 16 /dev/urandom |base64 |tr / ,)
输出类似于/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
(顺便说一句,我发现它给出的错误(ENOENT
)有点有趣。人们可能会认为它会说该名称无效,而不是它不存在.)
请注意,如果将其放入变量中,则在扩展它时确实需要记住引号!例如,f=; cat $f
只需从标准输入读取。
$ f=
$ cat "$f"
cat: '': No such file or directory
$ touch "$f"
touch: cannot touch '': No such file or directory
但是,如果您cd ""
在 shell 中执行此操作,它只会更改为当前目录。POSIX 说那“如果[给定路径]是空字符串,则结果未指定。”。我尝试的所有 shell 都明确使用调用中的当前路径chdir()
,例如:
/tmp$ strace -etrace=chdir zsh -c 'cd ""'
chdir("/tmp") = 0
+++ exited with 0 +++
/tmp$
我的这个想法是基于之前的(现在已删除) 回答。这可能是也可能不是特定于系统的,我只在 Linux 上尝试过。买者自负。
另外,正如评论中提到的,如果您不关心得到哪个确切的错误,或者使用甚至不告诉您的东西,例如[ -f ... ]
或[ -e ... ]
在 shell 中,您可以创建一个超长的文件名。
在几乎所有文件系统上,单个文件的最大长度为 255 或更小(请参阅文件系统比较维基百科上)。完整路径可以更长,但 256 字节的单个文件名是不可能的,并且给出ENAMETOOLONG
:
$ f=$(printf %256s x | tr ' ' x)
$ touch "$f"
touch: cannot touch 'xxx...xxx': File name too long
但是if [ -e "$f" ]; then ...
在我尝试过的所有 shell 中都没有错误(并且测试失败)。
(这POSIX 定义说这-e
是“假如果路径名无法解决”,但没有明确提及诊断。因此,我不确定某些实现可能会在某些情况下出错。请告诉您是否发现这种情况。)
(维基百科中的表格确实提到了两个每个文件长度较高的 Linux 文件系统,但我怀疑它们现在是否被广泛使用,而且我也了解 Linux 通常有 255 字节的限制,无论文件系统如何。)
答案4
特登已经给出了很好的答案:使用mktemp -d
。这篇文章以更基本的方式看待这个问题,并解释了为什么这个命令通常是最好的答案。
没有持续的永远不存在的路径。但根据你关于测试脚本的句子,这听起来像是多变的路径也一样好,只要脚本可以自行生成即可。
生成这样的路径的唯一方法是不断生成路径,直到生成的路径不存在为止。不幸的是,这可能会导致竞争条件: 其他程序可能会创建文件后你检查它是否存在,但是前您执行取决于该文件不存在的操作。
避免这种竞争条件的最佳方法是使用其他程序应该避免的路径,例如/tmp
.不幸的是,/tmp
往往是世界可写的,所以现在你有一个更大的问题:其他一些用户可能会创建该文件。
你真正想要的是一个其他程序应该避免的临时目录和其他用户无权访问。如果目录为空就更好了,这样您就可以使用该目录下的任何路径。
mktemp -d
创建一个满足上一段中所有标准的目录,同时保护自己免受其自身的竞争条件的影响。完成后,您可以使用rmdir
以下命令删除目录:
dir="$(mktemp -d)"
# Use "$dir"/foo as a nonexistent path.
rmdir "$dir"