【问题标题】:Running script with relative paths from another directory使用来自另一个目录的相对路径运行脚本
【发布时间】:2017-05-06 17:45:03
【问题描述】:

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

【问题讨论】:

  • 永远不要在脚本中使用相对路径,除非您在代码本身中设置当前目录。使用绝对路径或将所需目录附加到脚本开头的PATH

标签: linux bash relative-path


【解决方案1】:

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

#!/bin/bash
scriptdir="$(dirname "$0")"
cd "$scriptdir"

以下所有代码都将像在脚本目录中运行一样发生。

请注意,这是为了让脚本运行

  • 从脚本所在的文件夹,以及
  • 无论最初从何处调用脚本

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

基本原理

  • $0是运行脚本的完整路径。

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

      特殊参数

      shell 专门处理几个参数。这些参数可能 仅供参考;不允许分配给他们。
         ....

      0   扩展为 shell 或 shell 脚本的名称。这是设置在 shell 初始化。
         如果使用命令文件调用 bash, $0 设置为该文件的名称

         如果使用 -c 选项启动 bash,则设置 $0 到
         要执行的字符串之后的第一个参数,如果一个是 展示。否则设置为文件名
         用于调用bash, 由参数零给出。

  • dirname 返回其参数的路径

  • cd 改变当前目录

因此,每个顶部带有此代码的脚本都将运行,就好像当前在该目录中时输入了 ./script

从另一个角度来看

对于质量控制和冗余错误检查的措施,您可能需要实现一个包装函数,以检查特定文件夹结构或是否存在某些表明一切正确的文件。 (无论出于何种原因,dirnamecd 命令不起作用 - 我在这篇文章的底部有一个 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 "$0")"
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,当不需要进行彻底检查以说明脚本文件的符号链接等时。(再次......在可移植源中代码压缩包等,我非常怀疑是这种情况)。

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

我再次强调使用你所知道的为你需要的东西量身定制的东西 - 例如,通常认为使用dirname "$(readlink -f "$0")" 可能更“稳健”,但是,在 Mac OS X 上,会给你 readlink: illegal option -- f ,并且对可移植脚本没有真正的好处,但更适用于引用可能是符号链接和/或包含在 $PATH 目录中的已安装二进制文件的位置

【讨论】:

  • 谢谢你,很简单,做的工作。如果我有多个相互调用的脚本,那么每个脚本都有这些开头行是否安全?每个脚本都有自己独特的scriptdir 变量吗?
  • @Jona 是的,每个正在运行的实例,无论是相同的脚本还是其他,顶部的这些行都将$scriptdir 仅适用于该文件。 即使出于某种疯狂的原因,$scriptdir 是父 shell 中的导出环境变量,脚本中 $scriptdir 的设置仍会更新该脚本的值(不是父 shell 环境)
  • @Jona 我添加了一个额外的补充,它可能有助于在执行任何实际命令之前检查 scriptdir 和后续当前目录的设置。您显然会修改它以适合您的项目
  • 恭喜您的回复完整。
  • 可爱的答案!!
猜你喜欢
  • 2013-11-14
  • 2011-11-14
  • 2012-01-26
  • 2021-06-17
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
  • 2013-06-02
  • 1970-01-01
相关资源
最近更新 更多