我已经完成了一个BASH脚本,但是现在我需要为它添加接受插件的功能。
例如,该脚本可以将文件从一个文件系统位置移动到另一个文件系统位置。它目前编写利用mv
命令为此,但我想知道如何给用户选择做两件事:•用其他东西替换mv命令,
rsync
例如•重新定义整个move"函数的改进版本
我在网上找到了一些方法,但我不确定这是正确的方法。
"将mv命令替换为其他命令"的想法:
提供一个规范文档,定义所有可以替换的命令(及其相关的开关)。我想它还应该说明这些调整可以在哪里/如何进行。
用改进版本重新定义整个move函数的想法";
创建一个插件文件,其中包含一个与用户要重新定义的函数同名的函数。我相信这将覆盖给定函数的默认代码。
我想知道"正确的方法"。在概念层面上实现插件功能,以及如何在BASH脚本中具体实现。
定义接口
最重要的部分不是关于实现,而是关于文档和用法。你所依赖的每一个小细节都必须与用户沟通。
mv
可覆盖命令示例。使用惰性规范mv: Move "$1" to "$2"
,您的脚本可能会在以下情况下中断:
- 您使用
mv source1 source2 target/
- 您使用
mv -n source target
来防止覆盖现有文件 - 您假设
mv
在没有询问和错误的情况下覆盖现有目标。 - 你假设
mv
不打印任何东西,例如在var=$(mv a /tmp/; ls; mv /tmp/a ./)
。 - 假设
mv sourcedir/ targetdir/
和mv sourcedir targetdir
是相同的。提示:rsync
的行为改变基于尾斜杠
当您仔细定义了标准化接口后,您可以考虑实现。
2。实现一个插件系统
2.1使用bash
的默认行为(相当hacky)
从技术上讲,您不必在这里做任何事情,因为bash中的大多数命令已经是"插件",即$PATH
变量中指定的可执行二进制文件或脚本文件。
如果用户想要编写自己的mv
作为your_script.sh
的插件,他们已经可以运行…
mkdir /tmp/script_plugins
echo '#! /usr/bin/env bash
echo This is the mv plugin of the user
mv "$@"
' > /tmp/script_plugins/mv
chmod u+x /tmp/script_plugins/mv
export PATH="/tmp/script_plugins:$PATH"
./your_script.sh
…除非your_script.sh
再次覆盖PATH
或定义函数mv
或类似的东西。
2.2使用专用名称(cleaner)然而,为了更简洁,我会将插件定义为具有专用名称的函数,以强调这些函数可以被覆盖:
#! /usr/bin/env bash
# Content of your_script.sh
if declare -pf USER_PLUGIN_MV &> /dev/null; then
# user defined and exported a plugin function
plugable_mv() { "$USER_PLUGIN_MV" "$@"; }
else
# no plugin was specified, use default implementation
plugable_mv() { mv "$@"; }
fi
for i in "just" "an" "example"; do
plugable_mv "$i" target/
done
如果用户定义并导出一个名为USER_PLUGIN_MV
的函数,则该函数将被用于而不是默认的mv
命令。
USER_PLUGIN_MV() { echo "plugin received args: $*"; }
export -f USER_PLUGIN_MV
./your_script.sh
…打印…
plugin received args: just target/
plugin received args: an target/
plugin received args: example target/
2.3使用命令字符串或者,您可以让用户指定命令字符串(如xargs
、bash -c
或GNUparallel
中所见),例如. ...
./your_script.sh --replace-mv-with 'echo "plugin received args: $*"'
这些可以实现为…
# things starting with PSEUDO_ are pseudo code
if PSEUDO_user_specified_mv_plugin; then
plugable_mv() {
# either ...
bash -c "$PSEUDO_mv_plugin_arg" user_plugin_mv "$@"
# ... or if plugins have to access/define/alter your variables
eval "$mv_plugin_arg"
}
else
plugable_mv() { mv "$@"; }
fi
然而,嵌套引号一旦插件变大,就会给大多数用户带来严重的问题。所以,如果你实现了这个系统,我仍然建议你的用户使用导出函数…
USER_PLUGIN_MV() { echo "plugin received args: $*"; }
export -f USER_PLUGIN_MV
./your_script.sh --replace-mv-with 'USER_PLUGIN_MV "$@"'