我有一个Bash脚本,需要知道它的完整路径。我试图找到一种广泛兼容的方式来做到这一点,而不会以相对或时髦的路径结束。我只需要支持Bash,不支持sh, csh等。

到目前为止,我发现:

The accepted answer to Getting the source directory of a Bash script from within addresses getting the path of the script via dirname $0, which is fine, but that may return a relative path (like .), which is a problem if you want to change directories in the script and have the path still point to the script's directory. Still, dirname will be part of the puzzle. The accepted answer to Bash script absolute path with OS X (OS X specific, but the answer works regardless) gives a function that will test to see if $0 looks relative and if so will pre-pend $PWD to it. But the result can still have relative bits in it (although overall it's absolute) — for instance, if the script is t in the directory /usr/bin and you're in /usr and you type bin/../bin/t to run it (yes, that's convoluted), you end up with /usr/bin/../bin as the script's directory path. Which works, but... The readlink solution on this page, which looks like this: # Absolute path to this script. /home/user/bin/foo.sh SCRIPT=$(readlink -f $0) # Absolute path this script is in. /home/user/bin SCRIPTPATH=`dirname $SCRIPT` But readlink isn't POSIX and apparently the solution relies on GNU's readlink where BSD's won't work for some reason (I don't have access to a BSD-like system to check).

有很多种方法,但都有注意事项。

还有什么更好的办法呢?“更好”的意思是:

Gives me the absolute path. Takes out funky bits even when invoked in a convoluted way (see comment on #2 above). (E.g., at least moderately canonicalizes the path.) Relies only on Bash-isms or things that are almost certain to be on most popular flavors of *nix systems (GNU/Linux, BSD and BSD-like systems like OS X, etc.). Avoids calling external programs if possible (e.g., prefers Bash built-ins). (Updated, thanks for the heads up, wich) It doesn't have to resolve symlinks (in fact, I'd kind of prefer it left them alone, but that's not a requirement).


当前回答

Use:

SCRIPT_PATH=$(dirname `which $0`)

它将可执行文件的完整路径打印到标准输出,该路径是在shell提示符下输入传入参数时执行的($0包含该参数)

Dirname从文件名中去掉非目录后缀。

因此,无论是否指定了路径,您最终都会得到脚本的完整路径。

其他回答

以下是我所想到的(编辑:加上一些由sfstewman, levigroker, Kyle Strand和Rob Kennedy提供的调整),似乎基本上符合我的“更好”标准:

SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

SCRIPTPATH行似乎特别迂回,但为了正确地处理空格和符号链接,我们需要它而不是SCRIPTPATH= ' pwd '。

包含输出重定向(>/dev/null 2>&1)可以处理罕见的(?)情况,即cd可能产生的输出会干扰周围的$(…)捕捉。(例如cd被覆盖,也ls一个目录后切换到它。)

还要注意一些深奥的情况,比如执行一个根本不是来自可访问文件系统中的文件的脚本(这是完全可能的),不适合在那里(或者在我看到的任何其他答案中)。

cd后面和“$0”之前的——是为了防止目录以-开头。

再次考虑这个问题:在这个线程中引用了一个非常流行的解决方案,它的起源在这里:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

我一直没有使用这种解决方案,因为使用了dirname——它可能会带来跨平台的困难,特别是在出于安全原因需要锁定脚本的情况下。但是作为一个纯Bash的替代品,如何使用:

DIR="$( cd "$( echo "${BASH_SOURCE[0]%/*}" )" && pwd )"

这是一个选择吗?

我已经成功地使用了下面的方法一段时间(不是在OS X上),它只使用一个内置的shell,并处理'source foobar.sh'的情况,就我所见。

下面的示例代码的一个问题是,函数使用$PWD,在函数调用时,$PWD可能正确,也可能不正确。所以这需要处理。

#!/bin/bash

function canonical_path() {
  # Handle relative vs absolute path
  [ ${1:0:1} == '/' ] && x=$1 || x=$PWD/$1
  # Change to dirname of x
  cd ${x%/*}
  # Combine new pwd with basename of x
  echo $(pwd -P)/${x##*/}
  cd $OLDPWD
}

echo $(canonical_path "${BASH_SOURCE[0]}")

type [
type cd
type echo
type pwd

回答这个问题很晚,但我用:

SCRIPT=$( readlink -m $( type -p ${0} ))      # Full path to script handling Symlinks
BASE_DIR=`dirname "${SCRIPT}"`                # Directory script is run in
NAME=`basename "${SCRIPT}"`                   # Actual name of script even if linked

我今天不得不重新讨论这个问题,并从脚本本身中找到了获取Bash脚本的源目录:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

在链接的答案中有更多的变体,例如在脚本本身是符号链接的情况下。