通常包含脚本的方式是"source"

eg:

main.sh:

#!/bin/bash

source incl.sh

echo "The main script"

incl.sh:

echo "The included script"

执行“。/main.sh”的结果是:

The included script
The main script

... 现在,如果您试图从另一个位置执行该shell脚本,它将无法找到包含,除非它在您的路径中。

确保脚本能够找到包含脚本的好方法是什么,特别是在脚本需要可移植的情况下?


当前回答

个人将所有库放在lib文件夹中,并使用导入函数来加载它们。

文件夹结构

script.sh内容

# Imports '.sh' files from 'lib' directory
function import()
{
  local file="./lib/$1.sh"
  local error="\e[31mError: \e[0mCannot find \e[1m$1\e[0m library at: \e[2m$file\e[0m"
  if [ -f "$file" ]; then
     source "$file"
    if [ -z $IMPORTED ]; then
      echo -e $error
      exit 1
    fi
  else
    echo -e $error
    exit 1
  fi
}

注意,这个导入函数应该在脚本的开头,然后你可以像这样轻松地导入你的库:

import "utils"
import "requirements"

在每个库(例如utils.sh)的顶部添加一行:

IMPORTED="$BASH_SOURCE"

现在您可以从script.sh访问utils.sh和requirements.sh中的函数

待办事项:编写一个链接器来构建一个sh文件

其他回答

个人将所有库放在lib文件夹中,并使用导入函数来加载它们。

文件夹结构

script.sh内容

# Imports '.sh' files from 'lib' directory
function import()
{
  local file="./lib/$1.sh"
  local error="\e[31mError: \e[0mCannot find \e[1m$1\e[0m library at: \e[2m$file\e[0m"
  if [ -f "$file" ]; then
     source "$file"
    if [ -z $IMPORTED ]; then
      echo -e $error
      exit 1
    fi
  else
    echo -e $error
    exit 1
  fi
}

注意,这个导入函数应该在脚本的开头,然后你可以像这样轻松地导入你的库:

import "utils"
import "requirements"

在每个库(例如utils.sh)的顶部添加一行:

IMPORTED="$BASH_SOURCE"

现在您可以从script.sh访问utils.sh和requirements.sh中的函数

待办事项:编写一个链接器来构建一个sh文件

您需要指定其他脚本的位置,没有其他方法可以绕过它。我建议在你的脚本顶部设置一个可配置的变量:

#!/bin/bash
installpath=/where/your/scripts/are

. $installpath/incl.sh

echo "The main script"

或者,您可以坚持让用户维护一个环境变量来指示您的程序所在的位置,比如PROG_HOME或类似的变量。这可以通过在/etc/profile中创建带有该信息的脚本自动提供给用户D /,它将在用户每次登录时被引用。

Steve的回答绝对是正确的技术,但它应该被重构,以便您的installpath变量在一个单独的环境脚本中,所有这些声明都是在该脚本中进行的。

然后,所有脚本都以该脚本为源,如果安装路径发生更改,则只需在一个位置更改它。让事情更,呃,不受未来影响。天啊,我讨厌这个词!(-):

顺便说一句,当你以你的例子中所示的方式使用它时,你应该使用${installpath}引用变量:

. ${installpath}/incl.sh

如果省略大括号,一些shell将尝试展开变量“installpath/ include .sh”!

我建议您创建一个setenv脚本,其唯一目的是为整个系统中的各种组件提供位置。

然后,所有其他脚本将源此脚本,以便使用setenv脚本的所有脚本的所有位置都是通用的。

这在运行cronjobs时非常有用。当运行cron时,你会得到一个最小的环境,但是如果你让所有的cron脚本首先包含setenv脚本,那么你就能够控制和同步你想要cronjob在其中执行的环境。

我们在构建猴子上使用了这样的技术,用于跨大约2000 kSLOC的项目的持续集成。

使用source或$0不会为您提供脚本的真实路径。您可以使用脚本的进程id来检索它的实际路径

ls -l       /proc/$$/fd           | 
grep        "255 ->"            |
sed -e      's/^.\+-> //'

我正在使用这个脚本,它一直为我服务得很好:)