我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
当前回答
命名命令是最基本的,简单地将路径到0美元(脚本名称)变量的名称:
dirname -- "$0";
但是,正如Matt b指出的那样,返回的路径取决于脚本的名称。 pwd 不做工作,因为它只告诉你当前的目录是什么,而不是脚本的目录是什么。
有些人提到了阅读链接命令,但最简单的是,你可以使用:
dirname -- "$( readlink -f -- "$0"; )";
阅读链接将解决脚本路径从文件系统的根源到绝对路径,因此,任何包含单点或双点的路径,图标和/或象征性链接将解决到完整路径。
#!/usr/bin/env bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename -- "$0"`"
echo "dirname: `dirname -- "$0"`"
echo "dirname/readlink: $( dirname -- "$( readlink -f -- "$0"; )"; )"
在我的家中运行这个脚本,使用相对的路径:
>>>$ ./whatdir.sh
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat
再一次,但使用完整的路径到脚本:
>>>$ /Users/phatblat/whatdir.sh
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat
现在更改目录:
>>>$ cd /tmp
>>>$ ~/whatdir.sh
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat
最后,使用一个象征性的链接来执行脚本:
>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
然而,有一個案例,這不起作用,當脚本來源(而不是執行)在 bash:
>>>$ cd /tmp
>>>$ . ~/whatdir.sh
pwd: /tmp
$0: bash
basename: bash
dirname: .
dirname/readlink: /tmp
其他回答
最高答案在所有情况下都没有工作......
因此,让我们看看一个例子,这些替代的解决方案,为描述的任务,询问到一个特定的文件的真正绝对路径:
PATH_TO_SCRIPT=`realpath -s $0`
PATH_TO_SCRIPT_DIR=`dirname $PATH_TO_SCRIPT`
但最好你应该使用这个先进的版本,也支持使用路径与空间(或可能甚至一些其他特殊的字符):
PATH_TO_SCRIPT=`realpath -s "$0"`
PATH_TO_SCRIPT_DIR=`dirname "$PATH_TO_SCRIPT"`
下面存储了脚本的目录路径在Dir变量中。
(它也试图支持在Windows中的Cygwin下运行。
最后,它运行我的样本应用程序可执行,所有通过到这个脚本的论点使用“$@”:
#!/usr/bin/env sh
dir=$(cd "${0%[/\\]*}" > /dev/null && pwd)
if [ -d /proc/cygdrive ]; then
case "$(uname -s)" in
CYGWIN*|MINGW32*|MSYS*|MINGW*)
# We are under Windows, so translate path to Windows format.
dir=$(cygpath -m "$dir");
;;
esac
fi
# Runs the executable which is beside this script
"${dir}/my-sample-app" "$@"
基于这个答案,我建议一个明确的版本,获得SCRIPT_HOME作为包含任何目前运行的Bash脚本的文件夹:
s=${BASH_SOURCE[0]} ; s=`dirname $s` ; SCRIPT_HOME=`cd $s ; pwd`
echo $SCRIPT_HOME
#!/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'
使用阅读链接的组合来编码名称(如果是同链接,则将其返回来源的奖金)并提取目录名称:
script="`readlink -f "${BASH_SOURCE[0]}"`"
dir="`dirname "$script"`"