通常包含脚本的方式是"source"

eg:

main.sh:

#!/bin/bash

source incl.sh

echo "The main script"

incl.sh:

echo "The included script"

执行“。/main.sh”的结果是:

The included script
The main script

... 现在,如果您试图从另一个位置执行该shell脚本,它将无法找到包含,除非它在您的路径中。

确保脚本能够找到包含脚本的好方法是什么,特别是在脚本需要可移植的情况下?


当前回答

Shell脚本加载器是我的解决方案。

它提供了一个名为include()的函数,可以在许多脚本中多次调用该函数以引用单个脚本,但只加载脚本一次。该函数可以接受完整路径或部分路径(脚本在搜索路径中搜索)。还提供了一个名为load()的类似函数,它将无条件加载脚本。

它适用于bash, ksh, pd ksh和zsh与优化脚本为他们每一个;以及其他与原始sh兼容的shell,如ash、dash、传家宝sh等,通过一个通用脚本自动优化其功能,这取决于shell可以提供的特性。

(前进牌汽车的例子)

start.sh

这是一个可选的起始脚本。把启动方法放在这里只是为了方便,可以放在主脚本中。如果要编译脚本,也不需要这个脚本。

#!/bin/sh

# load loader.sh
. loader.sh

# include directories to search path
loader_addpath /usr/lib/sh deps source

# load main script
load main.sh

main.sh

include a.sh
include b.sh

echo '---- main.sh ----'

# remove loader from shellspace since
# we no longer need it
loader_finish

# main procedures go from here

# ...

a.sh

include main.sh
include a.sh
include b.sh

echo '---- a.sh ----'

b.sh

include main.sh
include a.sh
include b.sh

echo '---- b.sh ----'

输出:

---- b.sh ----
---- a.sh ----
---- main.sh ----

最好的是基于它的脚本也可以用可用的编译器编译成单个脚本。

下面是一个使用它的项目:http://sourceforge.net/p/playshell/code/ci/master/tree/。它可以在不编译脚本的情况下可移植地运行。还可以进行编译以生成单个脚本,这在安装期间很有帮助。

我还为任何想要简要了解实现脚本如何工作的保守党派创建了一个更简单的原型:https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash。它很小,任何人都可以将代码包含在他们的主脚本中,如果他们的代码打算在Bash 4.0或更新版本中运行,而且它也不使用eval。

其他回答

Shell脚本加载器是我的解决方案。

它提供了一个名为include()的函数,可以在许多脚本中多次调用该函数以引用单个脚本,但只加载脚本一次。该函数可以接受完整路径或部分路径(脚本在搜索路径中搜索)。还提供了一个名为load()的类似函数,它将无条件加载脚本。

它适用于bash, ksh, pd ksh和zsh与优化脚本为他们每一个;以及其他与原始sh兼容的shell,如ash、dash、传家宝sh等,通过一个通用脚本自动优化其功能,这取决于shell可以提供的特性。

(前进牌汽车的例子)

start.sh

这是一个可选的起始脚本。把启动方法放在这里只是为了方便,可以放在主脚本中。如果要编译脚本,也不需要这个脚本。

#!/bin/sh

# load loader.sh
. loader.sh

# include directories to search path
loader_addpath /usr/lib/sh deps source

# load main script
load main.sh

main.sh

include a.sh
include b.sh

echo '---- main.sh ----'

# remove loader from shellspace since
# we no longer need it
loader_finish

# main procedures go from here

# ...

a.sh

include main.sh
include a.sh
include b.sh

echo '---- a.sh ----'

b.sh

include main.sh
include a.sh
include b.sh

echo '---- b.sh ----'

输出:

---- b.sh ----
---- a.sh ----
---- main.sh ----

最好的是基于它的脚本也可以用可用的编译器编译成单个脚本。

下面是一个使用它的项目:http://sourceforge.net/p/playshell/code/ci/master/tree/。它可以在不编译脚本的情况下可移植地运行。还可以进行编译以生成单个脚本,这在安装期间很有帮助。

我还为任何想要简要了解实现脚本如何工作的保守党派创建了一个更简单的原型:https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash。它很小,任何人都可以将代码包含在他们的主脚本中,如果他们的代码打算在Bash 4.0或更新版本中运行,而且它也不使用eval。

我认为最好的方法是使用Chris Boran的方法,但是你应该这样计算MY_DIR:

#!/bin/sh
MY_DIR=$(dirname $(readlink -f $0))
$MY_DIR/other_script.sh

引用readlink的手册页:

Readlink -显示符号链接的值 ... - f,规范化 通过遵循给定组件中的每个符号链接进行规范化 递归地名称;除最后一个组件外,所有组件都必须存在

我从未遇到MY_DIR计算不正确的用例。如果你通过$PATH中的符号链接访问你的脚本,它就可以工作。

我知道我迟到了,但这应该工作,无论你如何开始脚本和使用内置专属:

DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
. "$DIR/incl.sh"
. "$DIR/main.sh"

. (dot)命令是source的别名,$PWD是工作目录的路径,BASH_SOURCE是一个数组变量,其成员是源文件名,${string%substring}从$string后面删除$substring的最短匹配

Steve的回答绝对是正确的技术,但它应该被重构,以便您的installpath变量在一个单独的环境脚本中,所有这些声明都是在该脚本中进行的。

然后,所有脚本都以该脚本为源,如果安装路径发生更改,则只需在一个位置更改它。让事情更,呃,不受未来影响。天啊,我讨厌这个词!(-):

顺便说一句,当你以你的例子中所示的方式使用它时,你应该使用${installpath}引用变量:

. ${installpath}/incl.sh

如果省略大括号,一些shell将尝试展开变量“installpath/ include .sh”!

当然,每个人都有自己的,但我认为下面的块是相当扎实的。我相信这涉及到查找目录的“最佳”方式,以及调用另一个bash脚本的“最佳”方式:

scriptdir=`dirname "$BASH_SOURCE"`
source $scriptdir/incl.sh

echo "The main script"

因此,这可能是包含其他脚本的“最佳”方式。这是基于另一个“最佳”答案,它告诉bash脚本它存储在哪里