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

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

$ ./application

当前回答

#!/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'

其他回答

下面将返回剧本的当前目录

工作,如果它是源,或者不源工作,如果运行在当前的目录,或某些其他目录.工作,如果相对目录被使用.工作与 bash,不确定其他<unk>。

/tmp/a/b/c $ . ./test.sh
/tmp/a/b/c

/tmp/a/b/c $ . /tmp/a/b/c/test.sh
/tmp/a/b/c

/tmp/a/b/c $ ./test.sh
/tmp/a/b/c

/tmp/a/b/c $ /tmp/a/b/c/test.sh
/tmp/a/b/c

/tmp/a/b/c $ cd

~ $ . /tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ . ../../tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ /tmp/a/b/c/test.sh
/tmp/a/b/c

~ $ ../../tmp/a/b/c/test.sh
/tmp/a/b/c

测试.sh

#!/usr/bin/env bash

# snagged from: https://stackoverflow.com/a/51264222/26510
function toAbsPath {
    local target
    target="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}

function getScriptDir(){
  local SOURCED
  local RESULT
  (return 0 2>/dev/null) && SOURCED=1 || SOURCED=0

  if [ "$SOURCED" == "1" ]
  then
    RESULT=$(dirname "$1")
  else
    RESULT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
  fi
  toAbsPath "$RESULT"
}

SCRIPT_DIR=$(getScriptDir "$0")
echo "$SCRIPT_DIR"

我不认为这是像其他人这样容易的。 pwd 不工作,因为当前的目录不一定是与脚本的目录。 $0 不总是有信息。

./script

/usr/bin/script

script

在第一和第三方式 $0 没有完整的路径信息. 在第二和第三, pwd 不工作. 唯一的方式来获得目录的第三方式将是通过路径运行并找到文件与正确的匹配。

做你正在要求的一种方式,就是在 /usr/share 目录中的数据硬编码,并将其引用到其完整的路径。

保持简单。

#!/usr/bin/env bash
sourceDir=`pwd`
echo $sourceDir

我会用这样的东西:

# Retrieve the full pathname of the called script
scriptPath=$(which $0)

# Check whether the path is a link or not
if [ -L $scriptPath ]; then

    # It is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # Otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

這是我多年來創造的,用作我的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 包含您需要的内容。