在这个询问 Ubuntu 帖子,我在未设置时使用 globstar 来定位文件PATH
:
$ shopt -s globstar; for v in /**/vim; do [[ -x $v && -f $v ]] && echo "$v"; done
/etc/alternatives/vim
/usr/bin/vim
/usr/bin/X11/vim
现在想来,这个输出似乎有点奇怪。/usr/bin/X11
是一个符号链接/usr/bin
:
$ readlink /usr/bin/X11
.
因此,那里有 s 的无限递归X11
,但只有第一个出现在输出中。奇怪的是,只是 a根本/usr/**
没有下降到:X11
$ printf "%s\n" /usr/bin/** | grep X11
/usr/bin/X11
如何协调第一个和最后一个输出?
来自评论:
我在 Ubuntu 16.04 上使用 Bash 版本 4.4.18(1)。
答案1
tl;dr - Bash 扩展很复杂,可以防止无限符号链接循环(在bash >= 4.3
),并且你和我都误解了它在你发布的命令中所做的事情
我假设你有,bash >= 4.3
因为我无法重现你在 中描述的内容bash 4.2.46
,它会循环直到达到递归限制(如预期)。
盯着这个看了一会儿,并设置了一个测试目录来模拟您的情况。关键在于 bash 扩展如何在每个示例中发生。根据扩展是否后跟 ,它的行为会有所不同/
,并且对于我们灵长类动物来说,在查看这样的示例时,在这一点上存在一些认知失调。
来自bash shopt 的文档:
globstar
如果设置,文件名扩展上下文中使用的模式“**”将匹配所有文件以及零个或多个目录和子目录。如果模式后跟“/”,则仅目录和子目录匹配。
为了说明这里是我的测试设置:
$ mkdir -p test/nested
$ cd test
$ touch sneaky
$ touch nested/sneaky
$ cd nested
$ ln -s . looper
$ cd ..
产生这样的目录结构:
test/
- sneaky
- nested/
- sneaky
- looper -> ./
这会重复您在我的测试目录中的发现:
$ for apath in ../**/sneaky; do echo "$apath"; done
../test/nested/looper/sneaky
../test/nested/sneaky
../test/sneaky
$ printf "%s\n" ../** | grep sneaky
../test/nested/sneaky
../test/sneaky
在第一个示例中,glob 扩展为(test/nested/looper, test/nested, test)
,在没有跟随链接的情况下停止,looper
因为 glob 后面跟着一个/
然后我们附加/sneaky
到它,得到集合(test/nested/looper/sneaky, test/nested/sneaky, test/sneaky)
。
在第二个示例中,glob 扩展为(test/nested/looper, test/nested/sneaky, test/nested, test/sneaky, test)
(您可以通过删除 来验证| grep sneaky
)
同样,此扩展不会遵循链接looper
,但在这种情况下,我们不会附加到它,从而从我们的结果中/sneaky
删除。../test/nested/looper/sneaky
另一方面,我们继续得到../test/nested/sneaky
和../test/sneaky
因为当 glob 后面没有跟随一个时也会抓取文件/