我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
当前回答
尝试一下这样的东西:
function get_realpath() {
if [[ -f "$1" ]]
then
# The file *must* exist
if cd "$(echo "${1%/*}")" &>/dev/null
then
# The file *may* not be local.
# The exception is ./file.ext
# tTry 'cd .; cd -;' *works!*
local tmppwd="$PWD"
cd - &>/dev/null
else
# file *must* be local
local tmppwd="$PWD"
fi
else
# The file *cannot* exist
return 1 # Failure
fi
# Reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # Success
}
function get_dirname(){
local realpath="$(get_realpath "$1")"
if (( $? )) # True when non-zero.
then
return $? # Failure
fi
echo "${realpath%/*}"
return 0 # Success
}
# Then from the top level:
get_dirname './script.sh'
# Or within a script:
get_dirname "$0"
# Can even test the outcome!
if (( $? )) # True when non-zero.
then
exit 1 # Failure
fi
這些功能和相關工具是我們的產品的一部分,已為社區提供免費,可以在GitHub找到作為 realpath-lib. 它是簡單的,清潔和良好的文档(很棒的學習),純粹的Bash,並沒有依賴。
source '/path/to/realpath-lib'
get_dirname "$0"
if (( $? )) # True when non-zero.
then
exit 1 # Failure
fi
其他回答
這是解決方案 e-satis 和 3bcdnlklvc04a 在他們的答案中指出的輕微改訂:
SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
SCRIPT_DIR="$PWD"
popd > /dev/null
}
这应该在他们列出的所有情况下仍然有效。
这将防止一个失败的冲动之后的Popd. 感谢控制台。
#!/bin/sh
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
PRG=`readlink "$PRG"`
done
scriptdir=`dirname "$PRG"`
pushd . > '/dev/null';
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}";
while [ -h "$SCRIPT_PATH" ];
do
cd "$( dirname -- "$SCRIPT_PATH"; )";
SCRIPT_PATH="$( readlink -f -- "$SCRIPT_PATH"; )";
done
cd "$( dirname -- "$SCRIPT_PATH"; )" > '/dev/null';
SCRIPT_PATH="$( pwd; )";
popd > '/dev/null';
它适用于所有版本,包括
当通过多个深度软链接呼叫时,当文件时,当脚本被命令“源”称为. (dot) 操作员时,当 arg $0 从呼叫器修改时,“./script” “/full/path/to/script” “/some/path/../../other/path/script” “./some/folder/script”
否则,如果Bash脚本本身是一个相对的Symlink,你想跟随它并返回链接到脚本的完整路径:
pushd . > '/dev/null';
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}";
while [ -h "$SCRIPT_PATH" ];
do
cd "$( dirname -- "$SCRIPT_PATH"; )";
SCRIPT_PATH="$( readlink -f -- "$SCRIPT_PATH"; )";
done
cd "$( dirname -- "$SCRIPT_PATH"; )" > '/dev/null';
SCRIPT_PATH="$( pwd; )";
popd > '/dev/null';
SCRIPT_PATH 以完整的路径提供,无论它是如何称呼的。
只需确保您在脚本开始时找到此处。
尝试使用:
real=$(realpath "$(dirname "$0")")
我通常将以下列入我的脚本的顶部,这在大多数情况下工作:
[ "$(dirname $0)" = '.' ] && SOURCE_DIR=$(pwd) || SOURCE_DIR=$(dirname $0);
ls -l $0 | grep -q ^l && SOURCE_DIR=$(ls -l $0 | awk '{print $NF}');
第一行根据PWD的值指定源,如果从当前路径运行,或者如果从其他地方呼叫,则命名。
第二行检查路径,以确定它是否是一个同链接,如果是这样,更新 SOURCE_DIR 到链接本身的位置。
可能有更好的解决方案在那里,但这是我成功的最干净的。