通常包含脚本的方式是"源"
例如:
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脚本,除非它在您的路径中,否则无法找到包含.
确保脚本可以找到包含脚本的好方法是什么,特别是如果脚本需要可移植的话?
我倾向于使我的脚本彼此相对.那样我就可以使用dirname:
#!/bin/sh my_dir="$(dirname "$0")" "$my_dir/other_script.sh"
我知道我迟到了,但无论你如何启动脚本并专门使用内置函数,这都应该有效:
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的最短匹配
替代方案:
scriptPath=$(dirname $0)
是:
scriptPath=${0%/*}
..优点是没有依赖于dirname,这不是内置命令(并不总是在模拟器中可用)
如果它位于同一目录中,则可以使用 dirname $0
:
#!/bin/bash source $(dirname $0)/incl.sh echo "The main script"
我认为最好的方法是使用Chris Boran的方式,但你应该这样计算MY_DIR:
#!/bin/sh MY_DIR=$(dirname $(readlink -f $0)) $MY_DIR/other_script.sh
引用readlink的手册页:
readlink - display value of a symbolic link ... -f, --canonicalize canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
我从来没有遇到过MY_DIR
没有正确计算的用例.如果你通过它的符号链接访问你的脚本$PATH
.
这个问题的答案组合提供了最强大的解决方案.
它在生产级脚本中为我们工作,具有很强的依赖性和目录结构支持:
#!/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
SRC=$(cd $(dirname "$0"); pwd) source "${SRC}/incl.sh"
即使脚本来源,这也有效:
source "$( dirname "${BASH_SOURCE[0]}" )/incl.sh"
我探讨了几乎所有的建议,这是最适合我的建议:
script_root=$(dirname $(readlink -f $0))
即使脚本符号链接到$PATH
目录,它也可以工作.
请在此处查看:https://github.com/pendashteh/hcagent/blob/master/bin/hcagent
2.最酷的# Copyright /sf/ask/17360801/ script_root=$(ls -l /proc/$$/fd | grep "255 ->" | sed -e 's/^.\+-> //')
这实际上来自这个页面上的另一个答案,但我也将它添加到我的答案中!
2.最可靠或者,在极少数情况下,这些不起作用,这是防弹方法:
# 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
希望这能帮到那里的人:)
另外,如果一个不适合您并提及您的操作系统和模拟器,请将其留作评论.谢谢!
您需要指定其他脚本的位置,没有其他方法.我建议在脚本的顶部放置一个可配置的变量:
#!/bin/bash installpath=/where/your/scripts/are . $installpath/incl.sh echo "The main script"
或者,您可以坚持要求用户维护一个环境变量,指示您的程序所在的位置,例如PROG_HOME或其他.这可以通过在/etc/profile.d/中创建包含该信息的脚本自动为用户提供,该脚本将在用户每次登录时获取.
我建议你创建一个setenv脚本,其唯一目的是为整个系统中的各种组件提供位置.
然后,所有其他脚本将获取此脚本,以便使用setenv脚本在所有脚本中使用所有位置.
这在运行cronjobs时非常有用.在运行cron时,您获得了最小的环境,但如果您首先使所有cron脚本都包含setenv脚本,那么您就可以控制和同步您希望cronjobs执行的环境.
我们在构建猴子上使用了这种技术,用于在大约2,000 kSLOC的项目中进行持续集成.