我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
当前回答
简短答案:
"`dirname -- "$0";`"
或(最好是):
"$( dirname -- "$0"; )"
其他回答
您可以做到这一点,只需将脚本名称($0)与 realpath 和/或 dirname 相结合,它适用于 Bash 和 Shell。
#!/usr/bin/env bash
RELATIVE_PATH="${0}"
RELATIVE_DIR_PATH="$(dirname "${0}")"
FULL_DIR_PATH="$(realpath "${0}" | xargs dirname)"
FULL_PATH="$(realpath "${0}")"
echo "RELATIVE_PATH->${RELATIVE_PATH}<-"
echo "RELATIVE_DIR_PATH->${RELATIVE_DIR_PATH}<-"
echo "FULL_DIR_PATH->${FULL_DIR_PATH}<-"
echo "FULL_PATH->${FULL_PATH}<-"
结果将是这样的:
# RELATIVE_PATH->./bin/startup.sh<-
# RELATIVE_DIR_PATH->./bin<-
# FULL_DIR_PATH->/opt/my_app/bin<-
# FULL_PATH->/opt/my_app/bin/startup.sh<-
$0 是脚本本身的名称
4.4 特殊变量类型
例如:LozanoMatheus/get_script_paths.sh
$0 不是一个可靠的方式来获得当前的脚本路径. 例如,这是我的.xprofile:
#!/bin/bash
echo "$0 $1 $2"
echo "${BASH_SOURCE[0]}"
# $dir/my_script.sh &
cd /tmp && ~/.xprofile && 来源 ~/.xprofile
/home/puchuu/.xprofile
/home/puchuu/.xprofile
-bash
/home/puchuu/.xprofile
因此,请使用 BASH_SURCE 代替。
没有<unk>(除了<unk>)和可以处理“陌生人”名称的形式,如那些有新闻,因为有些人会声称:
IFS= read -rd '' DIR < <([[ $BASH_SOURCE != */* ]] || cd "${BASH_SOURCE%/*}/" >&- && echo -n "$PWD")
#!/usr/bin/env bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
这是一个有用的单行,这将为您提供脚本的完整目录名称,无论它从哪里被召唤。
它将工作,只要找到脚本的路径的最后一个组成部分不是一个simlink(指南链接是OK)。如果你也想解决任何链接到脚本本身,你需要一个多线解决方案:
#!/usr/bin/env bash
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
SOURCE=$(readlink "$SOURCE")
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
最后一个将与任何结合的联盟,来源,bash -c,simlinks等工作。
注意:如果您在运行此剪辑之前将CD转到另一个目录,结果可能是错误的!
此外,请注意 $CDPATH gotchas 和 stderr 输出副作用,如果用户有明智的 overridden cd 将输出转向 stderr 而不是 (包括逃避序列,如在 Mac 上呼叫 update_terminal_cwd >&2 ) 添加 >/dev/null 2>&1 在您的 cd 命令结束时,将考虑到两种可能性。
要了解它是如何工作的,试着运行这个更垂直的形式:
#!/usr/bin/env bash
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET=$(readlink "$SOURCE")
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE=$TARGET
else
DIR=$( dirname "$SOURCE" )
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE=$DIR/$TARGET # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR=$( dirname "$SOURCE" )
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
它将打印一些类似:
SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
這是解決方案 e-satis 和 3bcdnlklvc04a 在他們的答案中指出的輕微改訂:
SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
SCRIPT_DIR="$PWD"
popd > /dev/null
}
这应该在他们列出的所有情况下仍然有效。
这将防止一个失败的冲动之后的Popd. 感谢控制台。