设想:
父文件夹包含许多子文件夹(例如数百个),其中包含可执行文件或源程序。比如说,父文件夹/opt/app1/bin/
包含许多子文件夹,mod1
, mod2
, ..., modn
。将它们全部添加到PATH
变量中可能会超出每行字符数限制,或者可能非常笨拙!
从用户dogbane的回答可以理解什么是通配符来选择目录中的所有目录那:
- 通配符
*/
可用于匹配目录,并且 - 通配符
**/*/
可用于匹配目录和子目录。
如果我将条目添加/opt/app1/bin/**/*/
到PATH
变量中,是否会在子文件夹中搜索搜索可执行文件?这样做会不会有什么并发症?
答案1
shell 中没有每行字符数限制。您可能会想到的是,如果命令行的长度以及当前环境变量及其值的集合太大,则无法执行外部命令。这仅在执行外部命令时(即,当 shell 必须使用 C 库的exec()
函数之一来启动其他可执行文件时)成为限制。设置变量的值并不执行任何外部命令。
您无法将文件名通配模式按原样添加到PATH
变量中,因为 shell 在使用该变量时不会对该变量执行文件名扩展。
您可以添加扩张PATH
如果您确保各个项目由 分隔,则将文件名通配模式添加到您的变量中:
。由于 的值中目录路径的分隔符PATH
是冒号,因此该路径名列表中包含的名称不能包含冒号。
在bash
shell 中,您可以针对您的模式/opt/app1/bin/**/*/
使用以下内容:
shopt -s globstar failglob
IFS=:$IFS
set -- /opt/app1/bin/**/*/
PATH=$PATH:"$*"
IFS=${IFS#?}
这会将位置参数列表设置为您的通配模式扩展到的扩展路径名列表(如果您愿意,您可以使用数组,但这会需要更多的输入)。然后将该列表扩展并添加到变量值的"$*"
末尾。PATH
"$*"
将 set 的第一个字符扩展IFS
为冒号将确保列表的元素由冒号分隔。
IFS
然后恢复原来的值。
failglob
如果没有模式匹配,我将用来终止脚本。如果您希望PATH
在没有与您的模式匹配的情况下保持不变,您可以使用
shopt -s globstar nullglob
IFS=:$IFS
set -- /opt/app1/bin/**/*/
PATH=$PATH${1+:"$*"}
IFS=${IFS#?}
这用于nullglob
代替failglob
并避免修改PATH
if$1
未定义,即,如果模式不匹配任何内容。
答案2
是的,添加扩张到/opt/app1/bin/**/*/
PATH 变量(假设您已经为 shell 设置了相应的选项以导致**
扩展)将导致在这些目录中搜索可执行文件。
请注意,此处的尾随*/
是无关的;您可以简单地使用 的扩展/opt/app1/bin/**/
来获取 下所有子目录的列表/opt/app1/bin
。
我没有看到长度限制$PATH 的 POSIX 规范,在基本定义 -- 环境变量 -- 其他环境变量中给出。
我能想象的并发症是:
屏蔽相同的命令——给定两个相同的可执行文件名称,找到的那个(并插入到 PATH 中)第一的将是默认调用的那个
未能找到错误命令时会出现额外的延迟(因为您的 shell 会在所有这些目录中搜索该命令)