当我运行以下命令时,Fedora 31 和 Debian 10 的行为有所不同:
/bin/ls /bin/!(znew) | /bin/grep znew
Fedora 它什么也不输出,但 Debian 却输出:
znew
znew
存在于 Fedora 上,如果我运行/bin/ls /bin/znew | /bin/grep znew
我会得到:
/bin/znew
(在 Debian 上也会发生同样的事情)
我检查了两个发行版上的 bash 配置,我发现的唯一区别是在 Fedora 上我有:
cdable_vars on
cdspell on
dirspell on
login_shell on
在 Debian 上,这些选项被禁用,并且extglob
在两个发行版上均已启用
注意:命令grep
仅用于此处以使列表更短
版本:
在 Fedora 上:5.0.11
在 Debian 上:5.0-4
为什么会存在这样的差异呢?
更新1
/bin 是 Debian 和 Fedora 上 /usr/bin 的符号链接。
这是在文件名中搜索 znew 字符串的输出:
updatedb && locate znew
/usr/bin/znew
/usr/share/man/man1/znew.1.gz
/var/lib/flatpak/runtime/org.freedesktop.Platform/x86_64/19.08/5a35247ad1c941455f2f9c4139d9136c6c0662e1b04e5b3c56121e7f67ba0100/files/bin/znew
/var/lib/lxc/centos/rootfs/usr/bin/znew
/var/lib/lxc/centos/rootfs/usr/share/man/man1/znew.1.gz
/var/lib/lxc/opensuse/rootfs/usr/bin/xznew
/var/lib/lxc/opensuse/rootfs/usr/bin/znew
/var/lib/lxc/opensuse/rootfs/usr/share/man/man1/xznew.1.gz
/var/lib/lxc/opensuse/rootfs/usr/share/man/man1/znew.1.gz
更新2
我发现了一些有趣的事情,Debian 中有一个 /bin/X11 的符号链接,.
删除后它的行为与 Fedora 中一样。
答案1
鉴于extglob
在交互式bash
会话中设置了 shell 选项,命令
ls /bin/!(znew) | grep znew
首先将ls
使用其中的所有名称运行/bin
,而不是znew
作为参数。如果此名称列表包含子目录的名称,ls
则将输出这些子目录的内容(因为-d
未与 一起使用ls
)。如果这些子目录之一包含 name znew
,则将grep
匹配并输出该名称。
的未知子目录的内容/bin
将被列出,ls
而不在其中的名称前面添加任何目录路径。因此,如果子目录包含名称znew
,它将被输出为znew
而不是 as /bin/some-dir/znew
。
何时ls
使用,如
ls /bin/znew | grep znew
它会输出字符串/bin/znew
而不是znew
(如果该路径名存在)。它这样做是因为它输出作为命令行参数给出的文件的特定路径名,而不是作为参数给出的目录的内容。
/usr/bin
如果有人尝试为被调用的/bin
while/bin
已经是符号链接/usr/bin
,或者 while/bin
仍然是目录创建符号链接,则可能会发生类似的情况。
在问题的更新中,发现这是到(当前目录)/bin/X11
的符号链接。.
这意味着znew
可以通过路径名访问/bin/X11/znew
。
所以,总而言之,发生的情况是/bin/!(znew)
通配模式扩展到路径名列表,其中之一是/bin/X11
(但不是/bin/znew
)。然后,该ls
实用程序将获取所有路径名,包括/bin/X11
作为参数的路径名。当ls
获取 list时,由于指向那里,因此列出了目录/bin/X11
的内容。然后实用程序会挑选出来,这将成为 的输出的一部分。/bin
/bin/X11
grep
znew
ls
饰演 史蒂芬·查泽拉斯在评论中指出/bin
,如果您的 Debian 系统上有一个文件的名称包含换行符后跟字符串znew
(可能后跟另一个换行符以及其他字符),您将获得相同的效果。
由于名称不完全是字符串znew
,因此它将与模式匹配/bin/!(znew)
并将ls
该单个名称输出为
/bin/something
znew
maybe more
并会从该输出中grep
提取。znew