通常包含脚本的方式是"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脚本,它将无法找到包含,除非它在您的路径中。

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


当前回答

这是一个很好的函数。它建立在@sacii所做的基础上。谢谢你!

它将允许您列出任意数量的空格分隔的脚本名称到source(相对于调用source_files的脚本)。

可选的是,你可以传递一个绝对路径或相对路径作为第一个参数,它将从那里来源。

您可以多次调用它(参见下面的示例)以从不同的dirs中获取脚本

#!/usr/bin/env bash

function source_files() {
  local scripts_dir
  scripts_dir="$1"

  if [ -d "$scripts_dir" ]; then
    shift
  else
    scripts_dir="${BASH_SOURCE%/*}"
    if [[ ! -d "$scripts_dir" ]]; then scripts_dir="$PWD"; fi
  fi

  for script_name in "$@"; do
    # shellcheck disable=SC1091 disable=SC1090
    . "$scripts_dir/$script_name.sh"
  done
}

下面是一个示例,您可以运行来展示如何使用它

#!/usr/bin/env bash

function source_files() {
  local scripts_dir
  scripts_dir="$1"

  if [ -d "$scripts_dir" ]; then
    shift
  else
    scripts_dir="${BASH_SOURCE%/*}"
    if [[ ! -d "$scripts_dir" ]]; then scripts_dir="$PWD"; fi
  fi

  for script_name in "$@"; do
    # shellcheck disable=SC1091 disable=SC1090
    . "$scripts_dir/$script_name.sh"
  done
}

## -- EXAMPLE -- ##
# assumes dir structure:
# /
#   source_files.sh
#   sibling.sh
#   scripts/
#     child.sh
#   nested/
#     scripts/
#       grandchild.sh

cd /tmp || exit 1

# sibling.sh
tee sibling.sh <<- EOF > /dev/null 
  #!/usr/bin/env bash
  
  export SIBLING_VAR='sibling var value'
EOF

# scripts/child.sh
mkdir -p scripts
tee scripts/child.sh <<- EOF > /dev/null
  #!/usr/bin/env bash

  export CHILD_VAR='child var value'
EOF

# nested/scripts/grandchild.sh
mkdir -p nested/scripts
tee nested/scripts/grandchild.sh <<- EOF > /dev/null
  #!/usr/bin/env bash

  export GRANDCHILD_VAR='grandchild var value'
EOF

source_files 'sibling'
source_files 'scripts' 'child'
source_files 'nested/scripts' 'grandchild'

echo "$SIBLING_VAR"
echo "$CHILD_VAR"
echo "$GRANDCHILD_VAR"

rm sibling.sh
rm -rf scripts nested

cd - || exit 1

打印:

sibling var value
child var value
grandchild var value

其他回答

个人将所有库放在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文件

我倾向于让我的脚本彼此相对。 这样我就可以使用dirname:

#!/bin/sh

my_dir="$(dirname "$0")"

"$my_dir/other_script.sh"

我把所有的启动脚本都放在。bashrc文件中。d目录。 这是在/etc/profile.之类的地方常用的技术d等。

while read file; do source "${file}"; done <<HERE
$(find ${HOME}/.bashrc.d -type f)
HERE

使用通配符解决方案的问题…

for file in ${HOME}/.bashrc.d/*.sh; do source ${file};done

...你的文件列表可能太长了。 一种方法是……

find ${HOME}/.bashrc.d -type f | while read file; do source ${file}; done

…运行但不按预期改变环境。

这应该可靠地工作:

source_relative() {
 local dir="${BASH_SOURCE%/*}"
 [[ -z "$dir" ]] && dir="$PWD"
 source "$dir/$1"
}

source_relative incl.sh

1. 最整齐的

我研究了几乎所有的建议,下面是对我有用的最简洁的建议:

Script_root =$(dirname $(readlink -f $0))

即使脚本被符号链接到$PATH目录,它也能工作。

在这里查看它的实际操作:https://github.com/pendashteh/hcagent/blob/master/bin/hcagent

2. 最酷的

# Copyright https://stackoverflow.com/a/13222994/257479
script_root=$(ls -l /proc/$$/fd | grep "255 ->" | sed -e 's/^.\+-> //')

这实际上是来自这一页上的另一个答案,但我也把它加到我的答案中!

3.最可靠

或者,在极少数情况下,这些方法都不起作用,下面是万无一失的方法:

# Copyright http://stackoverflow.com/a/7400673/257479
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 

script_root=$(dirname $(whereis_realpath "$0"))

你可以在taskrunner源代码:https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner中看到它的运行

希望这能帮助到一些人:)

此外,如果其中一个不适合你,请留下评论,并提到你的操作系统和模拟器。谢谢!