假设:
some.txt
dir
|-cat.sh
cat.sh包含内容:
cat ../some.txt
然后在./cat.sh
内运行dir
可以正常运行./dir/cat.sh
与dir
相同的级别。我希望这是由于不同的工作目录。是否容易将路径../some.txt
设置为cat.sh
的位置?
答案 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 。
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