运行 具有来自另一个目录的相对路径的脚本

Running script with relative paths from another directory

我正在编写脚本来编译代码。源位于许多不同的目录中。我要发布源代码,我希望它能被许多其他人编译。因此在我的脚本中我使用了相对路径。
如果某人 运行 在他的机器上从脚本所在的目录中获取脚本,例如 ./script 一切正常。但是,如果脚本是 运行 来自另一个目录,例如 ./path/to/script 那么路径不正确并且脚本不起作用。
我该如何克服这个问题?

一个简单的起点可能是将其添加到脚本的顶部:

#!/bin/bash
scriptdir="$(dirname "[=10=]")"
cd "$scriptdir"

所有以下代码都将出现,就好像它是 运行 在脚本目录中一样。

请注意,这是关于使脚本 运行

  • 从脚本所在的文件夹,以及
  • 不管最初从哪里调用脚本

这就是我怀疑你想要的,因为它是一个用于编译的脚本,因此它将放置在 src 树中一个非常特定的文件夹中(例如 configure 脚本或一种 makefile 形式)

理由

  • [=14=]是运行ning脚本的完整路径。

    • 来自 bash 人(我添加的格式):

      Special Parameters

      The shell treats several parameters specially. These parameters may only be referenced; assignment to them is not allowed.
         ....

      0   Expands to the name of the shell or shell script. This is set at shell initialization.
         If bash is invoked with a file of commands, [=33=] is set to the name of that file.

         If bash is started with the -c option, then [=33=] is set to the first argument after
         the string to be executed, if one is present. Otherwise, it is set to the file name
         used to invoke bash, as given by argument zero.

  • dirname returns 参数的路径

  • cd 改变当前目录

因此, 每个顶部带有此代码的脚本都将 运行ning 就好像 ./script 是当前在该目录中键入的一样。

换个角度来看

对于质量控制和冗余错误检查的措施,您可能想要实现一个包装函数来检查特定的文件夹结构或某些文件的存在,以表明一切都是正确的。 (无论出于何种原因,dirnamecd 命令不起作用 - 我在 post 的底部有一个 for Mac 的示例)。这个概念有两个方面:

  1. 您正在设置当前目录
  2. 您正在检查您所做的事情是否有效。

例如:

runcheck () {
versioncheck () {

head -n1 version | grep -q "### myapp V"

}

backout () {
echo "Problem verifying source paths.  Are you sure your archive is complete?"
exit
}

[ -d ./src ] && [ -d ./docs ] && [ -d ../myapp ] && (versioncheck) || backout 
    return
}

该代码将检查以下内容:

  • 目录src与可执行脚本
  • 存在于同一路径中
  • 目录docs与可执行脚本
  • 存在于同一路径中
  • 目录 myapp 存在于可执行脚本的下一级路径中
  • 在与可执行脚本相同的路径中有一个名为 version 的文件,并且第一行 包含字符串 ### myapp V(例如,对于 version 文件,其顶行可能显示为:### myapp V1.4 ###)

然后您可以将命令 runcheck 放在脚本中的任何位置,以验证您是否在正确的位置:

完整的实现示例:

#!/bin/bash

scriptdir="$(dirname "[=12=]")"
cd "$scriptdir"

runcheck () {
versioncheck () {
    head -n1 version | grep -q "### myapp V"
}   

backout () {
    echo "Problem verifying source paths.  Are you sure your archive is complete?"
    exit
}

[ -d ./src ] && [ -d ./docs ] && [ -d ../myapp ] && (versioncheck) || backout 
    return
}

runcheck #initial check at start of script

## bunch of code
## goes here

runcheck #just checking again

## bunch of code
## goes here

runcheck #final check before really doing something bad

## end of script

旁注/补充: 这将适用于 bash 当不需要进行彻底检查以说明脚本文件等的符号链接时。(这再次......在便携式源代码 tarball 等中,我非常怀疑是这种情况)。

我建议阅读此主题:Getting the source directory of a Bash script from within 如果您想要或曾经需要对此主题有透彻的了解,以便更全面地应用它。

我再次强调使用你所知道的为你的需要量身定做的东西——例如,它通常被认为更 "robust" 使用 dirname "$(readlink -f "[=31=]")" ,然而,在 Mac OS X 上,这会给你 readlink: illegal option -- f ,并且对可移植脚本没有真正的好处,但更适用于引用可能被符号链接的已安装二进制文件的位置 and/or 包含在 $PATH 目录中