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

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

$ ./application

当前回答

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

其他回答

关键部分是,我正在减少问题的范围:我禁止通过路径间接执行脚本(如 /bin/sh [脚本路径与路径组件有关])。

这可以被检测到,因为0美元将是一个相对的路径,不解决与当前文件夹有关的任何文件。我相信使用#!机制的直接执行总是导致绝对0美元,包括当脚本在路径上找到时。

我也要求在象征性链接链接链接的任何字符和字符只包含一个合理的字符子,特别是不是 \n, >, * 或?. 这对于字符逻辑来说是必要的。

#!/bin/sh
(
    path="${0}"
    while test -n "${path}"; do
        # Make sure we have at least one slash and no leading dash.
        expr "${path}" : / > /dev/null || path="./${path}"
        # Filter out bad characters in the path name.
        expr "${path}" : ".*[*?<>\\]" > /dev/null && exit 1
        # Catch embedded new-lines and non-existing (or path-relative) files.
        # $0 should always be absolute when scripts are invoked through "#!".
        test "`ls -l -d "${path}" 2> /dev/null | wc -l`" -eq 1 || exit 1
        # Change to the folder containing the file to resolve relative links.
        folder=`expr "${path}" : "\(.*/\)[^/][^/]*/*$"` || exit 1
        path=`expr "x\`ls -l -d "${path}"\`" : "[^>]* -> \(.*\)"`
        cd "${folder}"
        # If the last path was not a link then we are in the target folder.
        test -n "${path}" || pwd
    done
)

此分類上一篇: Mac OS X v10.6.6 (Snow Leopard):

DIR=$(cd "$(dirname "$0")"; pwd)

下面存储了脚本的目录路径在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" "$@"
#!/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'

dirname ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}

如果您想跟随同步链接,请使用您上面的路径上的阅读链接,重复或非重复。

#
# Location: test1/test2/test_script.sh
#
echo $0
echo $_
echo ${BASH_SOURCE}
echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}

cur_file="${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
cur_dir="$(dirname "${cur_file}")"
source "${cur_dir}/func_def.sh"

function test_within_func_inside {
    echo ${BASH_SOURCE}
    echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
}

echo "Testing within function inside"
test_within_func_inside

echo "Testing within function outside"
test_within_func_outside

#
# Location: test1/test2/func_def.sh
#
function test_within_func_outside {
    echo ${BASH_SOURCE}
    echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
}

BASH - 来源

一个序列变量,其成员是源文件名,在 FUNCNAME序列变量中定义了相应的序列函数名称。

功能

这个变量可以使用 BASH_LINENO 和 BASH_SOURCE. FUNCNAME 的每个元素都有相应的元素在 BASH_LINENO 和 BASH_SOURCE 描述呼叫板. 例如, ${FUNCNAME[$i]} 被呼叫从文件 ${BASH_SOURCE[$i+1]} 到线号 ${BASH_LINENO[$i]}。

(源:Bash手册)