我如何找到一个Bash脚本位于该脚本内部的目录的路径?

我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:

$ ./application

当前回答

$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 代替。

其他回答

选择的答案非常好,我把我的解决方案发送给任何人寻找更短的替代方案,这些解决方案仍然涉及来源、执行、完整路径、相对路径和同步链接,最后,这将在 macOS 上工作,因为不能假设GNU的核心路径的阅读链接版本可用。

GOTCHA是它不使用Bash,但它很容易在Bash脚本中使用,虽然OP没有在解决方案的语言上设置任何限制,但它可能是最好的,大多数人已经留在Bash世界中。

PHP 可在 macOS 默认情况下,并安装在其他平台上,但不一定是默认情况下. 我意识到这是一个缺点,但我会留下这个在这里,任何人来自搜索引擎,无论如何。

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"

下面是简单而正确的方式:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

解释:

${BASH_SOURCE[0]} - 完整的路径到脚本. 这个值将是正确的,即使脚本是源,例如源 <(echo 'echo $0') 打印 bash,同时取代它为 ${BASH_SOURCE[0]} 将打印整个路径的脚本。

此单行在 Cygwin 上工作,即使脚本已被从 Windows 称为 bash -c <script>:

set mydir="$(cygpath "$(dirname "$0")")"

使用“0”字母:

#!/usr/bin/env bash

echo "The script you are running has basename $( basename -- "$0"; ), dirname $( dirname -- "$0"; )";
echo "The present working directory is $( pwd; )";

使用 pwd 单独不会工作,如果您不从它包含的目录中运行脚本。

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

命名命令是最基本的,简单地将路径到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