我有一个使用相对路径的 bash 脚本。它需要有一个与存储脚本的目录相同的工作目录。只要我从提示符启动它,它就可以正常工作,因为我可以先 cd 到脚本的目录。但是,当我在 /etc/cron.hourly 中创建指向脚本的符号链接时,脚本会中断。
我需要一种方法使 bash 脚本将目录更改为存储脚本的目录。但是,到目前为止我还没有成功。即使脚本是通过符号链接从 cron 调用的,是否有一种简单的方法可以做到这一点?
答案1
正常情况下,shell 总是知道脚本的路径,因为它必须读取它。请注意,在某些情况下情况并非如此,例如setuid 脚本在支持它们的操作系统上(不是 Linux)——但 setuid shell 脚本无论如何都是一个坏主意。最重要的是,脚本可能在 shell 打开它的时间和您尝试使用它执行任何操作的时间之间发生了移动。因此,仅在不存在安全性或可靠性问题时才使用脚本的路径。具有已知结构的软件包是一个有效的用例。
传递给 shell 解释器的脚本路径可在特殊参数中找到$0
。这可能是相对路径,因此如果您要使用它,请在更改到另一个目录之前执行此操作。如果您知道脚本在此期间不会被移动,则可以使用它。
由于$0
可能是符号链接,因此您需要获取其目标。没有 POSIX 方法可以做到这一点,但在 Linux(GNU coreutils 或 BusyBox)和最近的 BSD 上您可以使用readlink -f
使用规范绝对路径。
script_path_in_package=$(readlink -f -- "$0")
script_directory=${script_path_in_package%/*}
请注意,这限制了您构建包的方式。例如,您不能将脚本放在独立于体系结构的目录树中,并在每个特定于体系结构的目录树内链接到它。
答案2
我不记得从哪里得到这个,所以我可以正确地归因,但我已经使用它很长时间来获取我正在执行的脚本的“规范”路径。我所说的规范,是指不带“.”的绝对路径。或其中的“..”。
CANON=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/$(basename -- "$0")")
如果需要,我将使用 $CANON 上的基本名称和目录名称来获取这些值。
答案3
你应该能够做到这一点。
- $0 参数扩展为调用脚本时的完整路径(包括名称)。
- 内置shell函数测试(或者[ ])可以使用以下命令测试路径是否是符号链接-L
ls -l
,如果应用于符号链接,将给出单行输出,并将真实路径作为最终字段。
这足以让您发现源头的位置。当然,这可能是一个符号链接,这需要您递归地执行此操作......
答案4
该变量$0
保存程序的名称。做
cd $(dirname $( readlink $0) )
更改到程序所在的目录。
是的,$0
可能有问题,如果用于一般情况。我认为在明确定义设置的特定情况下将其用于自己的工作是可以的。
特别是,脚本无论如何都不应该使用其目录进行工作,应该依赖环境变量或配置文件,所以为什么要关心“自从您启动脚本以来,有人可能已经移动了脚本”或如何 ksh 这样的细节将解释它(假设我们知道这是一个 bash 脚本)。