基于文件位置而不是当前工作目录的相对路径

时间:2014-06-09 01:52:10

标签: bash shell

假设:

some.txt
dir
 |-cat.sh

cat.sh包含内容:

cat ../some.txt

然后在./cat.sh内运行dir可以正常运行./dir/cat.shdir相同的级别。我希望这是由于不同的工作目录。是否容易将路径../some.txt设置为cat.sh的位置?

3 个答案:

答案 0 :(得分:99)

您要做的是获取脚本的绝对路径(可通过${BASH_SOURCE[0]}获得),然后使用此目录在脚本开头获取父目录和cd。 / p>

#!/bin/bash
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )

cd "$parent_path"
cat ../some.text

这将使您的shell脚本独立于您调用它的位置。每次运行时,就好像在./cat.sh内运行dir一样。

请注意,此脚本仅在您直接调用脚本(即不通过符号链接)时才有效,否则查找脚本的当前位置会变得更加棘手)

答案 1 :(得分:23)

@Martin Konecny's answer提供了正确的答案,但是 - 正如他所提到的 - 只有在不通过驻留在不同目录中的符号链接调用实际脚本时它才有效

这个答案涵盖了这种情况:解决方案,当通过符号链接或甚至符号链接 调用脚本时也可以使用:


Linux / GNU readlink 解决方案:

如果您的脚本只需要在 Linux 上运行,或者您知道readlink中有 GNU $PATH ,请使用{{1} },方便地将符号链接解析为终极目标:

readlink -f

请注意,GNU scriptDir=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")") 有3个相关选项,用于将符号链接解析为其最终目标的完整路径:readlink-f),--canonicalize({{ 1}})和-e--canonicalize-existing) - 请参阅-m 由于在此场景中存在定义的目标,因此可以使用3个选项中的任何一个;我在这里选择了--canonicalize-missing,因为它是最着名的一个。


多(类Unix)平台解决方案(包括具有仅POSIX 实用程序集的平台):

如果您的脚本必须在以下任何平台上运行:

  • 具有man readlink实用程序,但缺少-f选项(在GNU意义上将符号链接解析为其最终目标) - 例如, macOS

    • macOS使用readlink的BSD实现的旧版本;请注意,最新版本的FreeBSD / PC-BSD 支持支持-f
  • 甚至没有readlink,但有与POSIX兼容的实用程序 - 例如 HP-UX (谢谢@Charles Duffy)。

以下解决方案受https://stackoverflow.com/a/1116890/45375的启发, 定义辅助shell函数-f ,它将给定的符号链接解析为循环中的最终目标 - 此函数实际上是符合POSIX的GNU {{1}实现} readlink选项类似于rreadlink()选项,但最终目标必须存在

注意:该函数是 readlink 函数,并且仅在POSIX兼容时才使用仅符合POSIX标准的POSIX实用程序。对于以符合POSIX标准的shell代码(-e)编写的本身的此函数版本,请参阅here

  • 如果-f可用,则使用它(没有选项) - 在大多数现代平台上都是如此。

  • 否则,解析bash的输出,这是唯一符合POSIX的方法来确定符号链接的目标。
    警告:如果文件名或路径包含文字子串/bin/sh,这将会中断 - 但这不太可能。 (请注意,缺少readlink的平台可能仍然提供其他非POSIX方法来解析符号链接;例如,@ Charles Duffy提到支持ls -l格式字符的HP-UX的->实用程序。使用readlink主要版本;为了简洁起见,该函数不会尝试检测此类情况。)

  • 以下函数的可安装实用程序(脚本)形式(带有附加功能)可以在 rreadlink in the npm registry找到;在Linux和macOS上,用find安装;在其他平台上(假设他们有%l),请点击manual installation instructions

如果参数是符号链接,则返回最终目标的规范路径;否则,返回参数自己的规范路径。

-printf

答案 2 :(得分:1)

只需一行即可。

cat "`dirname $0`"/../some.txt