通常包含脚本的方式是"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脚本,它将无法找到包含,除非它在您的路径中。

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


当前回答

我在这里看到的大多数答案似乎都把事情复杂化了。这个方法对我来说一直很有效:

FULLPATH=$(readlink -f $0)
INCPATH=${FULLPATH%/*}

INCPATH将保存脚本的完整路径,不包括脚本文件名,无论脚本是如何调用的(通过$ path,相对或绝对)。

在此之后,只需要在同一目录中包含文件即可:

. $INCPATH/file_to_include.sh

参考:TecPorto /位置独立包括

其他回答

我建议您创建一个setenv脚本,其唯一目的是为整个系统中的各种组件提供位置。

然后,所有其他脚本将源此脚本,以便使用setenv脚本的所有脚本的所有位置都是通用的。

这在运行cronjobs时非常有用。当运行cron时,你会得到一个最小的环境,但是如果你让所有的cron脚本首先包含setenv脚本,那么你就能够控制和同步你想要cronjob在其中执行的环境。

我们在构建猴子上使用了这样的技术,用于跨大约2000 kSLOC的项目的持续集成。

您需要指定其他脚本的位置,没有其他方法可以绕过它。我建议在你的脚本顶部设置一个可配置的变量:

#!/bin/bash
installpath=/where/your/scripts/are

. $installpath/incl.sh

echo "The main script"

或者,您可以坚持让用户维护一个环境变量来指示您的程序所在的位置,比如PROG_HOME或类似的变量。这可以通过在/etc/profile中创建带有该信息的脚本自动提供给用户D /,它将在用户每次登录时被引用。

这个问题的答案的组合提供了最健壮的解决方案。

它在产品级脚本中工作,支持依赖关系和目录结构:

#!/bin/bash

# Full path of the current script
THIS=`readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0`

# The directory where current script resides
DIR=`dirname "${THIS}"`

# 'Dot' means 'source', i.e. 'include':
. "$DIR/compile.sh"

该方法支持所有这些:

路径中的空间 链接(通过readlink) ${BASH_SOURCE[0]}比$0更健壮

我把所有的启动脚本都放在。bashrc文件中。d目录。 这是在/etc/profile.之类的地方常用的技术d等。

while read file; do source "${file}"; done <<HERE
$(find ${HOME}/.bashrc.d -type f)
HERE

使用通配符解决方案的问题…

for file in ${HOME}/.bashrc.d/*.sh; do source ${file};done

...你的文件列表可能太长了。 一种方法是……

find ${HOME}/.bashrc.d -type f | while read file; do source ${file}; done

…运行但不按预期改变环境。

根据我的说法,脚本包含的合适位置是/usr/local/lib/

/usr/local/lib 与本地安装程序相关联的文件。

我个人更喜欢/usr/local/lib/bash/includes。 有bash-helper库用于以这种方式包含库:

#!/bin/bash

. /usr/local/lib/bash/includes/bash-helpers.sh

include api-client || exit 1                   # include shared functions
include mysql-status/query-builder || exit 1   # include script functions

# include script functions with status message
include mysql-status/process-checker; status 'process-checker' $? || exit 1
include mysql-status/nonexists; status 'nonexists' $? || exit 1