引用与$ PATH中的脚本相同目录下的文件


33

我有一个bash脚本文件,该文件放在添加到$ PATH的某个目录下,以便可以从任何目录调用该脚本。

在与脚本相同的目录下还有另一个文本文件。我想知道如何在脚本中引用文本文件吗?

例如,如果脚本仅用于输出文本文件的内容,cat textfile则将不起作用,因为当从其他目录调用脚本时,找不到文本文件。


最近出现了一个相关问题:通过符号链接执行时获取当前脚本的路径
Caleb,

这个问题回答了如何可靠地获取bash脚本文件路径,我将其添加到了我的路径:stackoverflow.com/q/4774054/1695680
ThorSummoner 2015年

Answers:


24

只要没有符号链接(在路径扩展或脚本本身中),这些命令就应该起作用:

  • MYDIR="$(dirname "$(realpath "$0")")"

  • MYDIR="$(dirname "$(which "$0")")"

  • 以上任何一个的两步版本:

    MYSELF="$(realpath "$0")"

    MYDIR="${MYSELF%/*}"

如果到脚本的路径上有符号链接,which则将提供一个答案,不包括该链接的解析。如果realpath您的系统上没有默认安装,则可以在此处找到

[编辑]:似乎与Caleb的建议realpath相比没有优势,所以最好使用后者。我的计时测试表明它实际上更快。readlink -f


没问题。顺便说一句,它realpath来自您的系统。(对于其他没有它的用​​户,可以使用readlink -f
Caleb,

@Caleb实际上我认为它属于标准GNU实用程序(coreutils)的集合,但是现在我可以看到它是一个单独的包
rozcietrzewiacz 2011年

@rozcietrzewiacz realpath可以追溯到GNU coreutils中(readlink -f甚至还有readlinkIIRC)(周围有几种类似的工具,readlink -f最终成为事实上的标准)。realpath仅保留它是为了与仍在使用它的脚本兼容。
吉尔(Gilles)“所以,别再邪恶了”,

$(dirname "$(which "$0")")$(dirname $0)哪里which不再存在的优势是什么?是不是一样
UlfR

readlink -f在Mac OS X 10.11.6上似乎不起作用,但是realpath开箱即用。
Grav's

9

我的系统没有realpath通过rozcietrzewiacz建议

您可以使用readlink命令完成此操作。与解析which或其他解决方案相比,使用此方法的优势在于,即使路径或执行的文件名的一部分是符号链接,您也可以找到实际文件所在的目录。

MYDIR="$(dirname "$(readlink -f "$0")")"

然后可以将您的文本文件读入如下变量:

TEXTFILE="$(<$MYDIR/textfile)"

@rozcietrzewiacz:实际上,我并不是仅指您的which建议。这个正常的解决方案涉及任一只是dirname或其组合cdpwd在子shell。Readlink在这里具有优势。无论如何,realpath似乎几乎只是一个包装readlink -f
卡莱布

我不知道realpath与的不同之处readlink -f。我只能看到它给了我相同的结果(而不是which)。
rozcietrzewiacz 2011年

请记住,readlink -f(来自GNU coreutils)不需要存在路径的最后一个元素readlink -e,但确实存在,但并不受的支持busybox readlink,后者模仿了-e他们的-f选择。
dragon788 '18 -10-1

8

$0脚本中的将是脚本的完整路径,dirname并将采用完整路径并仅提供目录,因此您可以执行以下操作以保存文本文件:

$ cat "$(dirname -- "$0")/textfile"

尽管这似乎不起作用,但realpath $0您说“ $0脚本中将是脚本的完整路径”是错误的。
rozcietrzewiacz 2011年

@roz用什么方式?
Michael Mrozek

1
$0是运行时的命令,例如../script.sh
rozcietrzewiacz 2011年

因此,实际上$(dirname "$0")相对路径返回到脚本,作为调用命令的一部分-而不是绝对路径。这可能导致脚本在运行时更改目录的问题。
rozcietrzewiacz 2011年

@roz啊,有趣。因此,我想这不会在这里引起问题,因为他在名称上调用了路径上的某些内容,但这会破坏其他内容。谢谢
Michael Mrozek

4

您可以将其放在脚本的顶部:

cd "${BASH_SOURCE%/*}" || exit

BASH_SOURCE内部bash变量实际上是一个路径名数组。如果将其扩展为简单的字符串,例如“ $ BASH_SOURCE”,则会得到第一个元素,即当前正在执行的函数或脚本的路径名。

资料来源:http : //mywiki.wooledge.org/BashFAQ/028


2

我正在尝试这些,而realpath对我不起作用。我去的解决方案是:

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

到目前为止效果很好。我想知道这种方法是否存在任何潜在问题。


1
很好,但是没有遵循符号链接。试试这个:SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
OronNavon

1

我用:

#! /bin/sh -
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) || exit
dosomethingwith "${dir%/}/some-file"

POSIX是POSIX,并且只要dirname $0不以换行符结尾,就可以正常工作-$CDPATH并且没有(也没有设置)(如果未在中查找脚本,可能还有其他一些特殊情况$PATH)。


0

我总是用来which从PATH查找可执行文件的完整路径。例如:

which python

如果将此与dirname命令结合使用,则会得到:

wp=`which python`
dn=`dirname $wp`
ls $dn
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.