六 脚本的批量 source

六 脚本的批量 source

【动机】

当入口 linux shell 脚本 main.sh, 在需要包含其他脚本的变量设置, 或者向当前会话添加其他脚本定义的函数等场景, 假设要 source 的文件分两部分, 分别位于项目文件夹以及公共的库文件夹下,一般采取以下形式(本文仅讨论不带参数的 source 语句):

# project folder:
source ./<path-to-target>/a.sh
source ./<path-to-target>/b.sh

# library folder:
source /<path-to-library/console.sh
source /<path-to-library/options.sh

这样书写本身没一点问题. 不过有几个缺点:

  1. source 列表可能会很长;
  2. 被 source 的文件修改文件名, 或者路径即使发生轻微改变, 也需要同步调整 source 列表

如何解决?

【意图】

利用 find 命令, 并指定包括及排除的目录/文件, 结合简单的 for 循环 source, 可一定程度缓解上述矛盾.

【实现】

为确保脚本正常运行, 推荐路径采用绝对路径. 以下代码应该置于入口脚本的头部:

# 项目根目录绝对路径
declare -r ROOT_DIR_PATH=$(dirname $(readlink -f $0))
# 公共库 library 绝对路径, 如果以上述路径为起点, 可能会有迂回
declare -r LNX_LIB_DIR="$ROOT_DIR_PATH/../../library"

# 当前入口脚本名称
declare -r ENTRY_FILE_NAME=${BASH_SOURCE[0]##*/}
# 当前入口脚本全路径
declare -r ENTRY_FILE_PATH=$ROOT_DIR_PATH/$ENTRY_FILE_NAME

# region Sourcing
for file in \
    $(find $ROOT_DIR_PATH \
        -type f -regex .*?\.sh$ \
        -not -wholename "$ENTRY_FILE_PATH" ) \
    $(find $LNX_LIB_DIR \
        -type f -regex .*?\.sh$ ) ; do
      source $file
done
# endregion Sourcing 

上述 #region Sourcing 部分, 第一个 find 命令必须显示排除入口脚本, 否则, 自己 source 自己, 还有王法吗?

当然也可以将两部分文件分别写入不同的 for 循环, 看个人习惯.

测试略

【备注】

当然这样的 source 方式, 也有缺点:

  1. 不能应对带参数的格式: source <filename> arg1 arg2 …
  2. 要求被 source 的文件, 先后顺序不会影响执行结果, 更不能导致运行错误. 对于设计良好的项目, 被 source 的脚本基本都是封装良好的函数集合以及必须的全局变量定义, 执行顺序由入口脚本编排, 所以这点一般不是问题.
  3. 一般不宜用作在入口脚本中, 直接执行其他脚本的形式(如果非要应用, 去掉 source 命令即可).
  4. 最后一个应该是不是缺点的缺点, 当被 source 的脚本位置变动幅度大到跳出项目目录或者库根目录, 此时只能老老实实一句一句 source 了.

注意, # region Sourcing 注释语句, 在后面使用 shc 将 linux shell 脚本编译成可执行文件中会用到, 这里先记下.