我今天得到了这行奇怪的代码,它告诉我“空”或“非空”,具体取决于 CWD 中是否有任何项目(除了.
and ..
)。
我想知道它是如何工作的,因为它对我来说毫无意义。
perl -le 'print+(q=not =)[2==(()=<.* *>)].empty'
我感兴趣的一点是<.* *>
。我不明白它如何获取目录中所有文件的名称。
这是一个打高尔夫球的单线。该-e
标志表示将命令行的其余部分作为程序执行。-l
启用自动线端处理。
该<.* *>
部分是一个包含两个要扩展的模式的 glob:.*
和*
.
这部分
(q=not =)
是一个包含单个值的列表——字符串“not”。这q=...=
是一个备用字符串分隔符,显然是因为单引号被用来引用单行。
该[...]
部分是该列表的下标。取决于此比较的结果,下标的值将是 0(值“not”)或 1(无,打印为空字符串):
2 == (()=<.* *>)
这里发生了很多事情。比较测试 glob 是否返回了正好两个项目的列表(假设是.
and ..
),但它是如何做到的却很棘手。内括号表示一个空列表。分配给此列表会将 glob 置于列表上下文中,以便它返回目录中的所有文件。(在标量上下文中,它的行为类似于迭代器,一次只返回一个。)赋值本身在标量上下文中进行评估(在比较的右侧),因此返回分配的元素数。
引导+
是防止 Perl 将列表解析为print
. 尾部.empty
将字符串“empty”连接到列表中的任何内容(即“not”或空字符串)。
<.* *>
是一个由两种模式组成的 glob:.*
都是以所有文件开头.
并*
对应于所有文件的文件名(这与通常的 DOS/Windows 约定不同)。
(()=<.* *>)
在列表上下文中计算 glob,返回所有匹配的文件名。
然后,比较2
将其放入标量上下文中,因此将其2
与返回的文件数进行比较。如果该数字是2
,那么唯一的目录条目是.
和..
,句点。;-)
<.* *>
意味着(glob(".*"), glob("*"))
。 glob
以与 shell 相同的方式扩展文件模式。
我发现该B::Deparse
模块在破译一些让大多数程序员眼花缭乱的东西方面有很大帮助,例如q=...=
结构:
$ perl -MO=Deparse,-p,-q,-sC 2>/dev/null << EOF
> print+(q=not =)[2==(()=<.* *>)].empty
> EOF
use File::Glob ();
print((('not ')[(2 == (() = glob('.* *')))] . 'empty'));
当然,这不会立即产生“可读”的代码,但它肯定会转换一些绊脚石。
该功能的文档在此处。(滚动到该部分的末尾附近)