extglob 在 Fedora 和 Debian 的 bash 中表现不同

extglob 在 Fedora 和 Debian 的 bash 中表现不同

当我运行以下命令时,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如果有人尝试为被调用的/binwhile/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/X11grepznewls


饰演 史蒂芬·查泽拉斯在评论中指出/bin,如果您的 Debian 系统上有一个文件的名称包含换行符后跟字符串znew(可能后跟另一个换行符以及其他字符),您将获得相同的效果。

由于名称不完全是字符串znew,因此它将与模式匹配/bin/!(znew)并将ls该单个名称输出为

/bin/something
znew
maybe more

并会从该输出中grep提取。znew

相关内容