在与当前脚本相同的目录中运行脚本

我在同一个文件夹中有两个 Bash 脚本(由下载整个存储库的用户保存) :

  • script.sh由用户运行
  • helper.sh是必需的,由 script.sh运行

这两个脚本应该在同一个目录中。我需要第一个脚本调用第二个脚本,但有两个问题:

  1. 了解当前的工作目录对我来说毫无用处,因为我不知道用户是如何执行第一个脚本的(可以是使用 /usr/bin/script.sh、使用 ./script.sh,也可以是使用 ../Downloads/repo/scr/script.sh)
  2. 在调用 helper.sh之前,脚本 script.sh将更改到另一个目录。

我完全可以通过将 工作目录存储在一个变量中来组装 Bash,但是对于我想象中非常普通和简单的任务来说,这段代码似乎没有必要那么复杂。

是否有一个标准的方法从 script.sh内部调用 helper.sh? 并将在任何 Bash 支持的操作系统中工作?

47928 次浏览

Since $0 holds the full path of the script that is running, you can use dirname against it to get the path of the script:

#!/bin/bash


script_name=$0
script_full_path=$(dirname "$0")


echo "script_name: $script_name"
echo "full path: $script_full_path"

so if you for example store it in /tmp/a.sh then you will see an output like:

$ /tmp/a.sh
script_name: /tmp/a.sh
full path: /tmp

so

  1. Knowing the current working directory is useless to me, because I don't know how the user is executing the first script (could be with /usr/bin/script.sh, with ./script.sh, or it could be with ../Downloads/repo/scr/script.sh)

Using dirname "$0" will allow you to keep track of the original path.

  1. The script script.sh will be changing to a different directory before calling helper.sh.

Again, since you have the path in $0 you can cd back to it.

$0 is considered unsafe and fragile by many devs. I have found another solution, it is safe for a chain of bash scripts and source.

If a.sh needs to execute b.sh (located in the same folder) using a child bash process:

#!/bin/bash
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
bash ${__dir}/b.sh

If a.sh needs to execute b.sh (located in the same folder) using the same bash process:

#!/bin/bash
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source ${__dir}/b.sh

Is there a standard way to reliably call helper.sh from within script.sh? And will work in any Bash-supported operating system?

In most cases, when helper.sh is in the same directory as script.sh, you can use in script.sh command:

. ${0%/*}/helper.sh

Explanation:
$0 stores the name of your process (in most cases it's the full path to your script).
${parameter%word} removes suffix pattern word from variable $parameter (in the command above it removes file name /* from the full path stored in variable $0).

If for some reasons (described in other answers) you don't want to use $0, you can use $BASH_SOURCE instead:

. ${BASH_SOURCE%/*}/helper.sh

And if you want, you can use source instead of .:

source ${BASH_SOURCE%/*}/helper.sh

As for me, it's the easiest way to achieve your goal.

You can use the $0 variable. But this won't be as simple as getting current script name:

d=${0%/*}
[ x"$d" = x"$0" ] && d=.   # portable variant, use [[ ...]] in bash freely
readonly d                 # optional, for additional safety


# ... later on
. "$d"/helper.sh


This works well in set -e case as well.