Bash:如何将其他脚本包括进来?

时间:2022-12-06 09:25:41

The way you would normally include a script is with "source"

通常包含脚本的方式是“源”

eg:

例如:

main.sh:

main.sh:

#!/bin/bash

source incl.sh

echo "The main script"

incl.sh:

incl.sh:

echo "The included script"

The output of executing "./main.sh" is:

执行的输出。/main。sh”是:

The included script
The main script

... Now, if you attempt to execute that shell script from another location, it can't find the include unless it's in your path.

…现在,如果您试图从另一个位置执行shell脚本,那么它就无法找到include,除非它在您的路径中。

What's a good way to ensure that your script can find the include script, especially if for instance, the script needs to be portable?

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

19 个解决方案

#1


186  

I tend to make my scripts all be relative to one another. That way I can use dirname:

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

#!/bin/sh

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

"$my_dir/other_script.sh"

#2


139  

I know I am late to the party, but this should work no matter how you start the script and uses builtins exclusively:

我知道我已经迟到了,但无论你如何启动脚本,并且只使用内置函数,这都是可行的。

DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
. "$DIR/incl.sh"
. "$DIR/main.sh"

. (dot) command is alias to source, $PWD is the Path for the Working Directory, BASH_SOURCE is an array variable whose members are the source filenames, ${string%substring} strips shortest match of $substring from back of $string

。(dot)命令是源的别名,$PWD是工作目录的路径,BASH_SOURCE是一个数组变量,它的成员是源文件名,${string%substring}从$string后面的$substring的最短匹配。

#3


49  

An alternative to:

另一种选择:

scriptPath=$(dirname $0)

is:

是:

scriptPath=${0%/*}

.. the advantage being not having the dependence on dirname, which is not a built-in command (and not always available in emulators)

. .不依赖dirname的好处是,它不是一个内置命令(也不总是在模拟器中可用)

#4


33  

If it is in the same directory you can use dirname $0:

如果是在同一个目录下,您可以使用dirname $0:

#!/bin/bash

source $(dirname $0)/incl.sh

echo "The main script"

#5


25  

I think the best way to do this is to use the Chris Boran's way, BUT you should compute MY_DIR this way:

我认为最好的方法是使用Chris Boran的方法,但是你应该这样计算MY_DIR:

#!/bin/sh
MY_DIR=$(dirname $(readlink -f $0))
$MY_DIR/other_script.sh

To quote the man pages for readlink:

为readlink引用手册页:

readlink - display value of a symbolic link

...

  -f, --canonicalize
        canonicalize  by following every symlink in every component of the given 
        name recursively; all but the last component must exist

I've never encountered a use case where MY_DIR is not correctly computed. If you access your script through a symlink in your $PATH it works.

我从来没有遇到过MY_DIR没有正确计算的用例。如果您通过$PATH中的一个符号链接访问您的脚本,它就会起作用。

#6


18  

SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/incl.sh"

#7


10  

This works even if the script is sourced:

即使脚本来源于此,也可以这样做:

source "$( dirname "${BASH_SOURCE[0]}" )/incl.sh"

#8


10  

All those solutions doesn't work for me.

所有这些解决方案对我都不起作用。

Please, use more robust method:

请使用更健壮的方法:

#!/bin/bash

# Full path of this script
THIS=`readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0`

# This directory path
DIR=`dirname "${THIS}"`

# 'Dot' means 'source', i.e. 'include'
. "$DIR/compile.sh"

It supports:

它支持:

  • Spaces in path
  • 空间的路径
  • Links (via readlink)
  • 通过指向链接()
  • ${BASH_SOURCE[0]} is more robust than $0
  • ${BASH_SOURCE[0]}比$0更健壮。

#9


7  

You need to specify the location of the other scripts, there is no other way around it. I'd recommend a configurable variable at the top of your script:

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

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

. $installpath/incl.sh

echo "The main script"

Alternatively, you can insist that the user maintain an environment variable indicating where your program home is at, like PROG_HOME or somesuch. This can be supplied for the user automatically by creating a script with that information in /etc/profile.d/, which will be sourced every time a user logs in.

或者,您可以坚持用户维护一个环境变量,该变量指示您的程序所在的位置,如PROG_HOME或somesuch。通过在/etc/ profile中创建一个包含该信息的脚本,可以自动为用户提供这一功能。d/,每次用户登录时,都将提供该服务。

#10


5  

I'd suggest that you create a setenv script whose sole purpose is to provide locations for various components across your system.

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

All other scripts would then source this script so that all locations are common across all scripts using the setenv script.

然后,所有其他脚本都将为这个脚本提供源代码,以便使用setenv脚本在所有脚本中使用所有位置。

This is very useful when running cronjobs. You get a minimal environment when running cron, but if you make all cron scripts first include the setenv script then you are able to control and synchronise the environment that you want the cronjobs to execute in.

这在运行cronjobs时非常有用。在运行cron时,您会得到一个最小的环境,但是如果您使所有cron脚本首先包含setenv脚本,那么您就能够控制和同步您希望cronjobs执行的环境。

We used such a technique on our build monkey that was used for continuous integration across a project of about 2,000 kSLOC.

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

#11


3  

Steve's reply is definitely the correct technique but it should be refactored so that your installpath variable is in a separate environment script where all such declarations are made.

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

Then all scripts source that script and should installpath change, you only need to change it in one location. Makes things more, er, futureproof. God I hate that word! (-:

然后,所有脚本源脚本和应该安装路径更改,您只需要在一个位置更改它。让事情变得更加,呃,未来。天啊,我讨厌这个词!(-):

BTW You should really refer to the variable using ${installpath} when using it in the way shown in your example:

顺便说一下,您应该使用${installpath}在您的示例中使用它时,使用${installpath}来引用变量:

. ${installpath}/incl.sh

If the braces are left out, some shells will try and expand the variable "installpath/incl.sh"!

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

#12


1  

Using source or $0 will not give you the real path of your script. You could use the process id of the script to retrieve its real path

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

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

I am using this script and it has always served me well :)

我正在使用这个脚本,它一直对我很好:)

#13


1  

I put all my startup scripts in a .bashrc.d directory. This is a common technique in such places as /etc/profile.d, etc.

我把所有的启动脚本都放在。bashrc中。d目录。在诸如/etc/profile.这样的地方,这是一种常见的技术。d等。

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

The problem with the solution using globbing...

使用globbing的解决方案的问题…

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

...is you might have a file list which is "too long". An approach like...

…您可能有一个“太长”的文件列表。这样的方法……

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

...runs but doesn't change the environment as desired.

运行,但不改变环境。

#14


1  

Of course, to each their own, but I think the block below is pretty solid. I believe this involves the "best" way to find a directory, and the "best" way to call another bash script:

当然,对每个人来说,我认为下面的街区是相当坚实的。我认为这涉及到找到一个目录的“最佳”方法,以及调用另一个bash脚本的“最佳”方法:

scriptdir=`dirname "$BASH_SOURCE"`
source $scriptdir/incl.sh

echo "The main script"

So this may be the "best" way to include other scripts. This is based off another "best" answer that tells a bash script where it is stored

因此,这可能是包含其他脚本的“最佳”方法。这是基于另一个“最佳”答案,它告诉bash脚本存储在哪里。

#15


1  

This should work reliably:

这应该工作可靠:

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

source_relative incl.sh

#16


1  

Shell Script Loader is my solution for this.

Shell脚本加载器是我的解决方案。

It provides a function named include() that can be called many times in many scripts to refer a single script but will only load the script once. The function can accept complete paths or partial paths (script is searched in a search path). A similar function named load() is also provided that will load the scripts unconditionally.

它提供了一个名为include()的函数,它可以在许多脚本中多次调用,以引用单个脚本,但是只加载一次脚本。该函数可以接受完整的路径或部分路径(在搜索路径中搜索脚本)。还提供了一个类似的函数load(),它将无条件地加载脚本。

It works for bash, ksh, pd ksh and zsh with optimized scripts for each one of them; and other shells that are generically compatible with the original sh like ash, dash, heirloom sh, etc., through a universal script that automatically optimizes its functions depending on the features the shell can provide.

它适用于bash、ksh、pd ksh和zsh,并为它们分别编写了优化的脚本;其他的外壳通常与原始的sh类似,如ash, dash, heirloom sh等等,通过一个通用的脚本,根据shell提供的特性自动优化其功能。

[Fowarded example]

(前进牌汽车的例子)

start.sh

start.sh

This is an optional starter script. Placing the startup methods here is just a convenience and can be placed in the main script instead. This script is also not needed if the scripts are to be compiled.

这是一个可选的启动脚本。在这里放置启动方法只是一个方便,可以放在主脚本中。如果要编译脚本,也不需要这个脚本。

#!/bin/sh

# load loader.sh
. loader.sh

# include directories to search path
loader_addpath /usr/lib/sh deps source

# load main script
load main.sh

main.sh

main.sh

include a.sh
include b.sh

echo '---- main.sh ----'

# remove loader from shellspace since
# we no longer need it
loader_finish

# main procedures go from here

# ...

a.sh

a.sh

include main.sh
include a.sh
include b.sh

echo '---- a.sh ----'

b.sh

b.sh

include main.sh
include a.sh
include b.sh

echo '---- b.sh ----'

output:

输出:

---- b.sh ----
---- a.sh ----
---- main.sh ----

What's best is scripts based on it may also be compiled to form a single script with the available compiler.

最好的是基于它的脚本也可以编译成一个单独的脚本和可用的编译器。

Here's a project that uses it: http://sourceforge.net/p/playshell/code/ci/master/tree/. It can run portably with or without compiling the scripts. Compiling to produce a single script can also happen, and is helpful during installation.

这里有一个使用它的项目:http://sourceforge.net/p/playshell/code/ci/master/tree/。它可以与或不编译脚本一起运行。编译生成一个单独的脚本也会发生,并且在安装过程中非常有用。

I also created a simpler prototype for any conservative party that may want to have a brief idea of how an implementation script works: https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash. It's small and anyone can just include the code in their main script if they want to if their code is intended to run with Bash 4.0 or newer, and it also doesn't use eval.

我还为任何可能想要了解实现脚本如何工作的保守方创建了一个更简单的原型:https://sourceforge.net/p/loader/code/ci/base/tree/loader- includeprototype.bash。它很小,任何人都可以在其主脚本中包含代码,如果他们想要使用Bash 4.0或更新的代码运行,而且它也不使用eval。

#17


0  

we just need to find out the folder where our incl.sh and main.sh is stored; just change your main.sh with this:

我们只需要找到我们的文件夹。sh存储;只是改变你的主。sh与:

main.sh

main.sh

#!/bin/bash

SCRIPT_NAME=$(basename $0)
SCRIPT_DIR="$(echo $0| sed "s/$SCRIPT_NAME//g")"
source $SCRIPT_DIR/incl.sh

echo "The main script"

#18


0  

1. Neatest

I explored almost every suggestion and here is the neatest one that worked for me:

我几乎探究了每一个建议,这是最适合我的建议:

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

script_root = $(目录名(指向- f 0美元)美元)

It works even when the script is symlinked to a $PATH directory.

即使脚本与$PATH目录相关联,它也可以工作。

See it in action here: https://github.com/pendashteh/hcagent/blob/master/bin/hcagent

请参见这里的操作:https://github.com/pendashteh/hcagent/blob/master/bin/hcagent。

2. The coolest

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

This is actually from another answer on this very page, but I'm adding it to my answer too!

这实际上是在这个页面上的另一个答案,但我也把它加到我的答案里!

2. The most reliable

Alternatively, in the rare case that those didn't work, here is the bullet proof approach:

或者,在极少数情况下,这些都不起作用,这里是防弹方法:

# Copyright http://*.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"))

You can see it in action in taskrunner source: https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner

您可以在taskrunner源代码中看到它的作用:https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner。

Hope this help someone out there :)

希望这能帮助到外面的人:

Also, please leave it as a comment if one did not work for you and mention your operating system and emulator. Thanks!

另外,如果你没有为你工作,并且提到你的操作系统和模拟器,请留下你的评论。谢谢!

#19


-3  

You can also use:

您还可以使用:

PWD=$(pwd)
source "$PWD/inc.sh"

#1


186  

I tend to make my scripts all be relative to one another. That way I can use dirname:

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

#!/bin/sh

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

"$my_dir/other_script.sh"

#2


139  

I know I am late to the party, but this should work no matter how you start the script and uses builtins exclusively:

我知道我已经迟到了,但无论你如何启动脚本,并且只使用内置函数,这都是可行的。

DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
. "$DIR/incl.sh"
. "$DIR/main.sh"

. (dot) command is alias to source, $PWD is the Path for the Working Directory, BASH_SOURCE is an array variable whose members are the source filenames, ${string%substring} strips shortest match of $substring from back of $string

。(dot)命令是源的别名,$PWD是工作目录的路径,BASH_SOURCE是一个数组变量,它的成员是源文件名,${string%substring}从$string后面的$substring的最短匹配。

#3


49  

An alternative to:

另一种选择:

scriptPath=$(dirname $0)

is:

是:

scriptPath=${0%/*}

.. the advantage being not having the dependence on dirname, which is not a built-in command (and not always available in emulators)

. .不依赖dirname的好处是,它不是一个内置命令(也不总是在模拟器中可用)

#4


33  

If it is in the same directory you can use dirname $0:

如果是在同一个目录下,您可以使用dirname $0:

#!/bin/bash

source $(dirname $0)/incl.sh

echo "The main script"

#5


25  

I think the best way to do this is to use the Chris Boran's way, BUT you should compute MY_DIR this way:

我认为最好的方法是使用Chris Boran的方法,但是你应该这样计算MY_DIR:

#!/bin/sh
MY_DIR=$(dirname $(readlink -f $0))
$MY_DIR/other_script.sh

To quote the man pages for readlink:

为readlink引用手册页:

readlink - display value of a symbolic link

...

  -f, --canonicalize
        canonicalize  by following every symlink in every component of the given 
        name recursively; all but the last component must exist

I've never encountered a use case where MY_DIR is not correctly computed. If you access your script through a symlink in your $PATH it works.

我从来没有遇到过MY_DIR没有正确计算的用例。如果您通过$PATH中的一个符号链接访问您的脚本,它就会起作用。

#6


18  

SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/incl.sh"

#7


10  

This works even if the script is sourced:

即使脚本来源于此,也可以这样做:

source "$( dirname "${BASH_SOURCE[0]}" )/incl.sh"

#8


10  

All those solutions doesn't work for me.

所有这些解决方案对我都不起作用。

Please, use more robust method:

请使用更健壮的方法:

#!/bin/bash

# Full path of this script
THIS=`readlink -f "${BASH_SOURCE[0]}" 2>/dev/null||echo $0`

# This directory path
DIR=`dirname "${THIS}"`

# 'Dot' means 'source', i.e. 'include'
. "$DIR/compile.sh"

It supports:

它支持:

  • Spaces in path
  • 空间的路径
  • Links (via readlink)
  • 通过指向链接()
  • ${BASH_SOURCE[0]} is more robust than $0
  • ${BASH_SOURCE[0]}比$0更健壮。

#9


7  

You need to specify the location of the other scripts, there is no other way around it. I'd recommend a configurable variable at the top of your script:

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

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

. $installpath/incl.sh

echo "The main script"

Alternatively, you can insist that the user maintain an environment variable indicating where your program home is at, like PROG_HOME or somesuch. This can be supplied for the user automatically by creating a script with that information in /etc/profile.d/, which will be sourced every time a user logs in.

或者,您可以坚持用户维护一个环境变量,该变量指示您的程序所在的位置,如PROG_HOME或somesuch。通过在/etc/ profile中创建一个包含该信息的脚本,可以自动为用户提供这一功能。d/,每次用户登录时,都将提供该服务。

#10


5  

I'd suggest that you create a setenv script whose sole purpose is to provide locations for various components across your system.

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

All other scripts would then source this script so that all locations are common across all scripts using the setenv script.

然后,所有其他脚本都将为这个脚本提供源代码,以便使用setenv脚本在所有脚本中使用所有位置。

This is very useful when running cronjobs. You get a minimal environment when running cron, but if you make all cron scripts first include the setenv script then you are able to control and synchronise the environment that you want the cronjobs to execute in.

这在运行cronjobs时非常有用。在运行cron时,您会得到一个最小的环境,但是如果您使所有cron脚本首先包含setenv脚本,那么您就能够控制和同步您希望cronjobs执行的环境。

We used such a technique on our build monkey that was used for continuous integration across a project of about 2,000 kSLOC.

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

#11


3  

Steve's reply is definitely the correct technique but it should be refactored so that your installpath variable is in a separate environment script where all such declarations are made.

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

Then all scripts source that script and should installpath change, you only need to change it in one location. Makes things more, er, futureproof. God I hate that word! (-:

然后,所有脚本源脚本和应该安装路径更改,您只需要在一个位置更改它。让事情变得更加,呃,未来。天啊,我讨厌这个词!(-):

BTW You should really refer to the variable using ${installpath} when using it in the way shown in your example:

顺便说一下,您应该使用${installpath}在您的示例中使用它时,使用${installpath}来引用变量:

. ${installpath}/incl.sh

If the braces are left out, some shells will try and expand the variable "installpath/incl.sh"!

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

#12


1  

Using source or $0 will not give you the real path of your script. You could use the process id of the script to retrieve its real path

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

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

I am using this script and it has always served me well :)

我正在使用这个脚本,它一直对我很好:)

#13


1  

I put all my startup scripts in a .bashrc.d directory. This is a common technique in such places as /etc/profile.d, etc.

我把所有的启动脚本都放在。bashrc中。d目录。在诸如/etc/profile.这样的地方,这是一种常见的技术。d等。

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

The problem with the solution using globbing...

使用globbing的解决方案的问题…

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

...is you might have a file list which is "too long". An approach like...

…您可能有一个“太长”的文件列表。这样的方法……

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

...runs but doesn't change the environment as desired.

运行,但不改变环境。

#14


1  

Of course, to each their own, but I think the block below is pretty solid. I believe this involves the "best" way to find a directory, and the "best" way to call another bash script:

当然,对每个人来说,我认为下面的街区是相当坚实的。我认为这涉及到找到一个目录的“最佳”方法,以及调用另一个bash脚本的“最佳”方法:

scriptdir=`dirname "$BASH_SOURCE"`
source $scriptdir/incl.sh

echo "The main script"

So this may be the "best" way to include other scripts. This is based off another "best" answer that tells a bash script where it is stored

因此,这可能是包含其他脚本的“最佳”方法。这是基于另一个“最佳”答案,它告诉bash脚本存储在哪里。

#15


1  

This should work reliably:

这应该工作可靠:

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

source_relative incl.sh

#16


1  

Shell Script Loader is my solution for this.

Shell脚本加载器是我的解决方案。

It provides a function named include() that can be called many times in many scripts to refer a single script but will only load the script once. The function can accept complete paths or partial paths (script is searched in a search path). A similar function named load() is also provided that will load the scripts unconditionally.

它提供了一个名为include()的函数,它可以在许多脚本中多次调用,以引用单个脚本,但是只加载一次脚本。该函数可以接受完整的路径或部分路径(在搜索路径中搜索脚本)。还提供了一个类似的函数load(),它将无条件地加载脚本。

It works for bash, ksh, pd ksh and zsh with optimized scripts for each one of them; and other shells that are generically compatible with the original sh like ash, dash, heirloom sh, etc., through a universal script that automatically optimizes its functions depending on the features the shell can provide.

它适用于bash、ksh、pd ksh和zsh,并为它们分别编写了优化的脚本;其他的外壳通常与原始的sh类似,如ash, dash, heirloom sh等等,通过一个通用的脚本,根据shell提供的特性自动优化其功能。

[Fowarded example]

(前进牌汽车的例子)

start.sh

start.sh

This is an optional starter script. Placing the startup methods here is just a convenience and can be placed in the main script instead. This script is also not needed if the scripts are to be compiled.

这是一个可选的启动脚本。在这里放置启动方法只是一个方便,可以放在主脚本中。如果要编译脚本,也不需要这个脚本。

#!/bin/sh

# load loader.sh
. loader.sh

# include directories to search path
loader_addpath /usr/lib/sh deps source

# load main script
load main.sh

main.sh

main.sh

include a.sh
include b.sh

echo '---- main.sh ----'

# remove loader from shellspace since
# we no longer need it
loader_finish

# main procedures go from here

# ...

a.sh

a.sh

include main.sh
include a.sh
include b.sh

echo '---- a.sh ----'

b.sh

b.sh

include main.sh
include a.sh
include b.sh

echo '---- b.sh ----'

output:

输出:

---- b.sh ----
---- a.sh ----
---- main.sh ----

What's best is scripts based on it may also be compiled to form a single script with the available compiler.

最好的是基于它的脚本也可以编译成一个单独的脚本和可用的编译器。

Here's a project that uses it: http://sourceforge.net/p/playshell/code/ci/master/tree/. It can run portably with or without compiling the scripts. Compiling to produce a single script can also happen, and is helpful during installation.

这里有一个使用它的项目:http://sourceforge.net/p/playshell/code/ci/master/tree/。它可以与或不编译脚本一起运行。编译生成一个单独的脚本也会发生,并且在安装过程中非常有用。

I also created a simpler prototype for any conservative party that may want to have a brief idea of how an implementation script works: https://sourceforge.net/p/loader/code/ci/base/tree/loader-include-prototype.bash. It's small and anyone can just include the code in their main script if they want to if their code is intended to run with Bash 4.0 or newer, and it also doesn't use eval.

我还为任何可能想要了解实现脚本如何工作的保守方创建了一个更简单的原型:https://sourceforge.net/p/loader/code/ci/base/tree/loader- includeprototype.bash。它很小,任何人都可以在其主脚本中包含代码,如果他们想要使用Bash 4.0或更新的代码运行,而且它也不使用eval。

#17


0  

we just need to find out the folder where our incl.sh and main.sh is stored; just change your main.sh with this:

我们只需要找到我们的文件夹。sh存储;只是改变你的主。sh与:

main.sh

main.sh

#!/bin/bash

SCRIPT_NAME=$(basename $0)
SCRIPT_DIR="$(echo $0| sed "s/$SCRIPT_NAME//g")"
source $SCRIPT_DIR/incl.sh

echo "The main script"

#18


0  

1. Neatest

I explored almost every suggestion and here is the neatest one that worked for me:

我几乎探究了每一个建议,这是最适合我的建议:

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

script_root = $(目录名(指向- f 0美元)美元)

It works even when the script is symlinked to a $PATH directory.

即使脚本与$PATH目录相关联,它也可以工作。

See it in action here: https://github.com/pendashteh/hcagent/blob/master/bin/hcagent

请参见这里的操作:https://github.com/pendashteh/hcagent/blob/master/bin/hcagent。

2. The coolest

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

This is actually from another answer on this very page, but I'm adding it to my answer too!

这实际上是在这个页面上的另一个答案,但我也把它加到我的答案里!

2. The most reliable

Alternatively, in the rare case that those didn't work, here is the bullet proof approach:

或者,在极少数情况下,这些都不起作用,这里是防弹方法:

# Copyright http://*.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"))

You can see it in action in taskrunner source: https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner

您可以在taskrunner源代码中看到它的作用:https://github.com/pendashteh/taskrunner/blob/master/bin/taskrunner。

Hope this help someone out there :)

希望这能帮助到外面的人:

Also, please leave it as a comment if one did not work for you and mention your operating system and emulator. Thanks!

另外,如果你没有为你工作,并且提到你的操作系统和模拟器,请留下你的评论。谢谢!

#19


-3  

You can also use:

您还可以使用:

PWD=$(pwd)
source "$PWD/inc.sh"