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

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

$ ./application

当前回答

大多数答案都不会处理通过相对路径连接的文件,不是单线或不处理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

其他回答

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

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

解释:

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

最高答案在所有情况下都没有工作......

因此,让我们看看一个例子,这些替代的解决方案,为描述的任务,询问到一个特定的文件的真正绝对路径:

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"`

這是我多年來創造的,用作我的Bash寫作的標題:

## BASE BRAIN - Get where you're from and who you are.
MYPID=$$
ORIGINAL_DIR="$(pwd)" # This is not a hot air balloon ride..
fa="$0" # First Assumption
ta= # Temporary Assumption
wa= # Weighed Assumption
while true; do
    [ "${fa:0:1}" = "/" ] && wa=$0 && break
    [ "${fa:0:2}" = "./" ] && ta="${ORIGINAL_DIR}/${fa:2}" && [ -e "$ta" ] && wa="$ta" && break
    ta="${ORIGINAL_DIR}/${fa}" && [ -e "$ta" ] && wa="$ta" && break
done
SW="$wa"
SWDIR="$(dirname "$wa")"
SWBIN="$(basename "$wa")"
unset ta fa wa
( [ ! -e "$SWDIR/$SWBIN" ] || [ -z "$SW" ] ) && echo "I could not find my way around :( possible bug in the TOP script" && exit 1

此时此刻,您的变量 SW、SWDIR 和 SWBIN 包含您需要的内容。

$_ 值得提到为 $0 的替代品。 如果您正在运行来自 Bash 的脚本,可将接受的答案缩短到:

DIR="$( dirname "$_" )"

请注意,这应该是您的脚本中的第一个声明。

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