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

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


当前回答

替代:

scriptPath=$(dirname $0)

is:

scriptPath=${0%/*}

. .优点是不依赖于dirname,这不是一个内置命令(在模拟器中并不总是可用)。

其他回答

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

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

引用readlink的手册页:

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

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

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

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

. $installpath/incl.sh

echo "The main script"

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

1. 最整齐的

我研究了几乎所有的建议,下面是对我有用的最简洁的建议:

Script_root =$(dirname $(readlink -f $0))

即使脚本被符号链接到$PATH目录,它也能工作。

在这里查看它的实际操作:https://github.com/pendashteh/hcagent/blob/master/bin/hcagent

2. 最酷的

# Copyright https://stackoverflow.com/a/13222994/257479
script_root=$(ls -l /proc/$$/fd | grep "255 ->" | sed -e 's/^.\+-> //')

这实际上是来自这一页上的另一个答案,但我也把它加到我的答案中!

3.最可靠

或者,在极少数情况下,这些方法都不起作用,下面是万无一失的方法:

# Copyright http://stackoverflow.com/a/7400673/257479
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 

script_root=$(dirname $(whereis_realpath "$0"))

你可以在taskrunner源代码:https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner中看到它的运行

希望这能帮助到一些人:)

此外,如果其中一个不适合你,请留下评论,并提到你的操作系统和模拟器。谢谢!

使用source或$0不会为您提供脚本的真实路径。您可以使用脚本的进程id来检索它的实际路径

ls -l       /proc/$$/fd           | 
grep        "255 ->"            |
sed -e      's/^.\+-> //'

我正在使用这个脚本,它一直为我服务得很好:)

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

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

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

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