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

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

$ ./application

当前回答

最短、最优雅的方式就是:

#!/bin/bash
DIRECTORY=$(cd `dirname $0` && pwd)
echo $DIRECTORY

它会在所有平台上工作,而且非常干净。

更多详细信息可在“该 bash 脚本在哪个目录?”中找到。

其他回答

下面是一个命令,在Bash或zsh下工作,以及是否单独执行或源:

[ -n "$ZSH_VERSION" ] && this_dir=$(dirname "${(%):-%x}") \
    || this_dir=$(dirname "${BASH_SOURCE[0]:-$0}")

它是如何工作的

Fallback 替代操作员:

% x=ok
% echo "${x}"
ok

% echo "${x:-fallback}"
ok

% x=
% echo "${x:-fallback}"
fallback

% y=yvalue
% echo "${x:-$y}"
yvalue

此分類上一篇: %x prompt escape code

接下来,我们将引入即时逃避代码,一个 zsh-only 功能. 在 zsh 中, %x 将扩展到文件的路径,但通常只有在进行即时行扩展时。

% cat apath/test.sh
fpath=%x
echo "${(%)fpath}"

% source apath/test.sh
apath/test.sh

% cd apath
% source test.sh
test.sh

% cat test.sh
echo "${(%):-%x}"

% source test.sh
test.sh

请注意,我们通常会把变量名称放在(%)和(%)之间,但我们留下了白色。

我们可能已经使用打印 -P %x 以获得相同的文件路径,有更少的黑客,但在我们的情况下,我们需要将其作为一个论点转到一个字符串,这将需要一个开始一个新的字符串的顶部:

% cat apath/test.sh
dirname "$(print -P %x)"  # $(...) runs a command in a new process
dirname "${(%):-%x}"

% source apath/test.sh
apath
apath

显然,黑客的方式既更有效又更简短。

没有<unk>(除了<unk>)和可以处理“陌生人”名称的形式,如那些有新闻,因为有些人会声称:

IFS= read -rd '' DIR < <([[ $BASH_SOURCE != */* ]] || cd "${BASH_SOURCE%/*}/" >&- && echo -n "$PWD")

大多数答案都不会处理通过相对路径连接的文件,不是单线或不处理BSD(Mac)。

HERE=$(cd "$(dirname "$BASH_SOURCE")"; cd -P "$(dirname "$(readlink "$BASH_SOURCE" || echo .)")"; pwd)

首先, cd 到 bash 的概念的脚本的目录. 然后 readlink 文件,以查看它是否是一个 symlink (相对或其他), 如果是这样, cd 到该目录. 否则, cd 到当前目录(需要保持事物一个单线)。 然后 echo 当前目录通过 pwd。

你可以添加 - 到CD和阅读链接的论点,以避免名为选项的目录问题,但我不在乎大多数目的。

你可以看到完整的解释与图像在这里:

https://www.binaryphile.com/bash/2020/01/12/determining-the-location-of-your-script-in-bash.html

尝试一下这样的东西:

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

pwd 可以用来找到当前工作目录,而 dirname 可以用来找到特定文件的目录(运行命令为 $0,所以 dirname $0 应该给你当前脚本的目录)。

然而,字体名称给出了字体名称的目录部分,这更有可能与当前工作目录无关,如果你的脚本需要因某种原因更改目录,那么字体名称的输出就会变得毫无意义。

我建议如下:

#!/usr/bin/env bash

reldir="$( dirname -- "$0"; )";
cd "$reldir";
directory="$( pwd; )";

echo "Directory is ${directory}";

这样,你就得到一个绝对的,而不是一个相对的目录。

由于脚本将在一个单独的Bash例子中运行,没有必要恢复工作目录后,但如果你想因某种原因改变你的脚本,你可以轻松地将PWD的值分配给一个变量,在你更改目录之前,用于未来的使用。

雖然只是

cd "$( dirname -- "$0"; )";

解决这个问题的具体场景,我发现有绝对的道路到更有用的一般。