首页 > 解决方案 > bash 中是否可以自动加载惰性(类似 ksh)函数?

问题描述

我的项目(来自 ksh 的端口)使用一些目录作为可自动加载的功能。在这些目录中,每个文件名都作为在文件中声明的函数的名称,获取该文件以声明(实现)该函数。每个目录都可以被认为是一个“包”,它通过函数增加了 bash 内置集。我有大约 20 个包,每个包的功能数量可能很大(在某些包中可以达到 30 个)。


bash 文档包含一个自动加载的示例实现:

https://www.apt-browse.org/browse/ubuntu/trusty/main/all/bash-doc/4.3-6ubuntu1/file/usr/share/doc/bash/examples/functions/autoload.v2

但是,该实现需要在 shell 启动时知道(和枚举)一组可能自动加载的函数。

没有这种限制的实现是可能的吗?

标签: bashfunctionautoload

解决方案


这是第二个实现,以避免在之前的实现中看到的信号使用和看起来不太稳定的 command_not_found_handle() 的使用。

autoload::
function autoload
{ local d="$1" && [ "$1" ] && shift && autoload "$@"  
  local identifier='^[_a-zA-Z][_a-zA-Z0-9]*$'
  [ -d "$d"  -a -x "$d" ] && cd "$d" &&
  { for f in *
    do [[ $f =~ $identifier ]] && alias $f=". $PWD/$f;unalias $f;$f"
    done
    cd ->/dev/null 2>&1
  }
}


autoload $@  $(IFS=:; echo $FPATH)

在这里,我们再次在 rc 文件或脚本中获取这个 autolaod 文件。

FPATH 的使用并不是真正需要的(有关 FPATH 的更多详细信息,请参阅注释)

所以基本上这个想法是获取自动加载文件以及一组要查找的目录。

PW$ . /path/to/autoload a1 a2
PW$ alias | grep 'a[12c]_*'
alias a1_f1='. /home/phi/a1/a1_f1;unalias a1_f1;a1_f1'
alias a1_f2='. /home/phi/a1/a1_f2;unalias a1_f2;a1_f2'
alias a2_f1='. /home/phi/a2/a2_f1;unalias a2_f1;a2_f1'
alias ac_f3='. /home/phi/a1/ac_f3;unalias ac_f3;ac_f3'

PW$ declare -F |  grep 'a[12c]_*'

在自动加载采购之后,我们得到了所有定义的别名并且没有函数。

这比以前的实现要重一些,但非常轻量级,在 shell 中创建别名并不昂贵,即使有数百个。

PW$ a1_f1 11a 11b 11c
In a1_f1() : args=11a 11b 11c

PW$ a2_f1 21a 21b 21c
In a2_f1() : args=21a 21b 21c

PW$ alias | grep 'a[12c]_*'
alias a1_f2='. /home/phi/a1/a1_f2;unalias a1_f2;a1_f2'
alias ac_f3='. /home/phi/a1/ac_f3;unalias ac_f3;ac_f3'
PW$ declare -F |  grep 'a[12c]_*'

declare -f a1_f1
declare -f a2_f1

在这里,我们看到 a1_f1() 和 a2_f2() 被加载并执行,它们从别名列表中删除并添加到函数列表中。

PW$ a1_f2 12a 12b 12c
a1_f2: command not found

PW$ ac_f3 c3a c3b c3c
In a1 ac_f3() : args=c3a c3b c3c

PW$ qqq 

Command 'qqq' not found, did you mean:

  command 'qrq' from snap qrq (0.3.1)
  command 'qrq' from deb qrq

See 'snap info <snapname>' for additional versions.

在这里,我们看到 a1_f2() 没有找到,不像之前的实现那样被很好地报告。

ac_f3() 是来自 a1/ 的那个。

如果安装了 qqq 仍然会提供 command-not-found 发行包结果(正常我们没有弄乱 command_not_found_handle() )

优点和缺点

专业人士 不是坐在 bash 错误上,即在 bash 更新后可以存活一段时间。

缺点 比以前的实现要重一些,但可以接受。

简单得多,可能并不简单,但肯定比 bash 文档中建议的示例更短,并且更懒惰,即仅在必要时加载函数(虽然不是别名)

多功能“包”文件以及用于外部 API 暴露的硬链接的性能较差,因为每个外部 API 函数(硬链接)都会触发文件的重新加载,除非包文件写得很好,在加载后删除了所有多余的别名。


推荐阅读