当 bash 脚本以 . 操作员?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/421772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can a bash script know the directory it is installed in when it is sourced with . operator?
提问by Gary
What I'd like to do is to include settings from a file into my current interactive bash shell like this:
我想要做的是将文件中的设置包含到我当前的交互式 bash shell 中,如下所示:
$ . /path/to/some/dir/.settings
$ . /path/to/some/dir/.settings
The problem is that the .settings script also needs to use the "." operator to include other files like this:
问题是 .settings 脚本也需要使用“.”。运算符以包含其他文件,如下所示:
. .extra_settings
. .extra_settings
How do I reference the relative path for .extra_settings in the .settings file? These two files are always stored in the same directory, but the path to this directory will be different depending on where these files were installed.
如何在 .settings 文件中引用 .extra_settings 的相对路径?这两个文件总是存储在同一个目录中,但是根据这些文件的安装位置,该目录的路径会有所不同。
The operator always knows the /path/to/some/dir/ as shown above. How can the .settings file know the directory where it is installed? I would rather not have an install process that records the name of the installed directory.
操作员总是知道 /path/to/some/dir/ ,如上所示。.settings 文件如何知道它的安装目录?我宁愿没有记录安装目录名称的安装过程。
回答by Jason Day
I believe $(dirname "$BASH_SOURCE")will do what you want, as long as the file you are sourcing is nota symlink.
我相信$(dirname "$BASH_SOURCE")会做你想做的,只要你采购的文件不是符号链接。
If the file you are sourcing may be a symlink, you can do something like the following to get the true directory:
如果您正在采购的文件可能是一个符号链接,您可以执行以下操作来获取真正的目录:
PRG="$BASH_SOURCE"
progname=`basename "$BASH_SOURCE"`
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
dir=$(dirname "$PRG")
回答by Jacob Lee
Here is what might be an elegant solution:
这可能是一个优雅的解决方案:
script_path="${BASH_SOURCE[0]}"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"
This will not, however, work when sourcing links. In that case, one might do
但是,这在采购链接时不起作用。在那种情况下,人们可能会这样做
script_path="$(readlink -f "$(readlink "${BASH_SOURCE[0]}")")"
script_dir="$(cd "$(dirname "${script_path}")" && pwd)"
Things to note:
注意事项:
- arrays like
${array[x]}are not POSIX compliant - but then, theBASH_SOURCEarray is only available in Bash, anyway - on macOS, the native BSD
readlinkdoes not support-f, so you might have to install GNUreadlinkusing e.g. brewbybrew install coreutilsand replacereadlinkbygreadlink - depending on your use case, you might want to use the
-eor-mswitches instead of-fplus possibly-n; see readlinkman page for details
回答by orip
A different take on the problem - if you're using "." in order to set environment variables, another standard way to do this is to have your script echo variable setting commands, e.g.:
对问题的不同看法 - 如果您使用“。” 为了设置环境变量,另一种标准方法是让您的脚本回显变量设置命令,例如:
# settings.sh
echo export CLASSPATH=${CLASSPATH}:/foo/bar
then eval the output:
然后评估输出:
eval $(/path/to/settings.sh)
That's how packages like moduleswork. This way also makes it easy to support shells derived from sh (X=...; export X) and csh (setenv X ...)
这就是像模块这样的包的工作方式。这种方式也可以很容易地支持从 sh( X=...; export X) 和 csh( setenv X ...)派生的 shell
回答by Gary
I tried messing with variants of $(dirname $0) but it fails when the .settings file is included with ".". If I were executing the .settings file instead of including it, this solution would work. Instead, the $(dirname $0) always returns ".", meaning current directory. This fails when doing something like this:
我尝试弄乱 $(dirname $0) 的变体,但是当 .settings 文件包含在“.”中时它失败了。如果我正在执行 .settings 文件而不是包含它,则此解决方案将起作用。相反,$(dirname $0) 总是返回“.”,表示当前目录。执行以下操作时会失败:
$ cd / $ . /some/path/.settings
$ cd / $。/some/path/.settings
回答by Gary
This sort of works. It works in the sense that you can use the $(dirname $0) syntax within the .settings file to determine its home since you are executing this script in a new shell. However, it adds an extra layer of convolution where you need to change lines such as:
这样的作品。它的工作原理是,您可以在 .settings 文件中使用 $(dirname $0) 语法来确定其主页,因为您是在新 shell 中执行此脚本。但是,它增加了一个额外的卷积层,您需要在其中更改行,例如:
export MYDATE=$(date)
to
到
echo "export MYDATE=$(date)"
Maybe this is the only way?
也许这是唯一的方法?

